Merge "[veridex] Resolve all type_id/method_id/field_id in app dex files."
diff --git a/compiler/optimizing/code_sinking.cc b/compiler/optimizing/code_sinking.cc
index f4760d6..2e31d35 100644
--- a/compiler/optimizing/code_sinking.cc
+++ b/compiler/optimizing/code_sinking.cc
@@ -214,6 +214,11 @@
DCHECK(target_block != nullptr);
}
+ // Bail if the instruction can throw and we are about to move into a catch block.
+ if (instruction->CanThrow() && target_block->GetTryCatchInformation() != nullptr) {
+ return nullptr;
+ }
+
// Find insertion position. No need to filter anymore, as we have found a
// target block.
HInstruction* insert_pos = nullptr;
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 2b6f905..0b2297d 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -852,7 +852,7 @@
static HInstruction* NewIntegralAbs(ArenaAllocator* allocator,
HInstruction* x,
HInstruction* cursor) {
- DataType::Type type = x->GetType();
+ DataType::Type type = DataType::Kind(x->GetType());
DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
HAbs* abs = new (allocator) HAbs(type, x, cursor->GetDexPc());
cursor->GetBlock()->InsertInstructionBefore(abs, cursor);
@@ -865,7 +865,7 @@
HInstruction* y,
HInstruction* cursor,
bool is_min) {
- DataType::Type type = x->GetType();
+ DataType::Type type = DataType::Kind(x->GetType());
DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
HBinaryOperation* minmax = nullptr;
if (is_min) {
@@ -939,9 +939,9 @@
DataType::Type t_type = true_value->GetType();
DataType::Type f_type = false_value->GetType();
// Here we have a <cmp> b ? true_value : false_value.
- // Test if both values are same-typed int or long.
- if (t_type == f_type &&
- (t_type == DataType::Type::kInt32 || t_type == DataType::Type::kInt64)) {
+ // Test if both values are compatible integral types (resulting
+ // MIN/MAX/ABS type will be int or long, like the condition).
+ if (DataType::IsIntegralType(t_type) && DataType::Kind(t_type) == DataType::Kind(f_type)) {
// Try to replace typical integral MIN/MAX/ABS constructs.
if ((cmp == kCondLT || cmp == kCondLE || cmp == kCondGT || cmp == kCondGE) &&
((a == true_value && b == false_value) ||
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 9b37017..6950b93 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1609,11 +1609,9 @@
// Unzip or copy dex files straight to the oat file.
std::vector<std::unique_ptr<MemMap>> opened_dex_files_map;
std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
- // No need to verify the dex file for:
- // 1) Dexlayout since it does the verification. It also may not pass the verification since
- // we don't update the dex checksum.
- // 2) when we have a vdex file, which means it was already verified.
- const bool verify = !DoDexLayoutOptimizations() && (input_vdex_file_ == nullptr);
+ // No need to verify the dex file when we have a vdex file, which means it was already
+ // verified.
+ const bool verify = (input_vdex_file_ == nullptr);
if (!oat_writers_[i]->WriteAndOpenDexFiles(
vdex_files_[i].get(),
rodata_.back(),
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 5590c8b..0cd39ac 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -2013,4 +2013,84 @@
ASSERT_EQ(vdex_unquickened->FlushCloseOrErase(), 0) << "Could not flush and close";
}
+// Test that compact dex generation with invalid dex files doesn't crash dex2oat. b/75970654
+TEST_F(Dex2oatTest, CompactDexInvalidSource) {
+ ScratchFile invalid_dex;
+ {
+ FILE* file = fdopen(invalid_dex.GetFd(), "w+b");
+ ZipWriter writer(file);
+ writer.StartEntry("classes.dex", ZipWriter::kAlign32);
+ DexFile::Header header = {};
+ StandardDexFile::WriteMagic(header.magic_);
+ StandardDexFile::WriteCurrentVersion(header.magic_);
+ header.file_size_ = 4 * KB;
+ header.data_size_ = 4 * KB;
+ header.data_off_ = 10 * MB;
+ header.map_off_ = 10 * MB;
+ header.class_defs_off_ = 10 * MB;
+ header.class_defs_size_ = 10000;
+ ASSERT_GE(writer.WriteBytes(&header, sizeof(header)), 0);
+ writer.FinishEntry();
+ writer.Finish();
+ ASSERT_EQ(invalid_dex.GetFile()->Flush(), 0);
+ }
+ const std::string dex_location = invalid_dex.GetFilename();
+ const std::string odex_location = GetOdexDir() + "/output.odex";
+ std::string error_msg;
+ int status = GenerateOdexForTestWithStatus(
+ {dex_location},
+ odex_location,
+ CompilerFilter::kQuicken,
+ &error_msg,
+ { "--compact-dex-level=fast" });
+ ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) != 0) << status << " " << output_;
+}
+
+// Test that dex2oat with a CompactDex file in the APK fails.
+TEST_F(Dex2oatTest, CompactDexInZip) {
+ CompactDexFile::Header header = {};
+ CompactDexFile::WriteMagic(header.magic_);
+ CompactDexFile::WriteCurrentVersion(header.magic_);
+ header.file_size_ = sizeof(CompactDexFile::Header);
+ header.data_off_ = 10 * MB;
+ header.map_off_ = 10 * MB;
+ header.class_defs_off_ = 10 * MB;
+ header.class_defs_size_ = 10000;
+ // Create a zip containing the invalid dex.
+ ScratchFile invalid_dex_zip;
+ {
+ FILE* file = fdopen(invalid_dex_zip.GetFd(), "w+b");
+ ZipWriter writer(file);
+ writer.StartEntry("classes.dex", ZipWriter::kCompress);
+ ASSERT_GE(writer.WriteBytes(&header, sizeof(header)), 0);
+ writer.FinishEntry();
+ writer.Finish();
+ ASSERT_EQ(invalid_dex_zip.GetFile()->Flush(), 0);
+ }
+ // Create the dex file directly.
+ ScratchFile invalid_dex;
+ {
+ ASSERT_GE(invalid_dex.GetFile()->WriteFully(&header, sizeof(header)), 0);
+ ASSERT_EQ(invalid_dex.GetFile()->Flush(), 0);
+ }
+ std::string error_msg;
+ int status = 0u;
+
+ status = GenerateOdexForTestWithStatus(
+ { invalid_dex_zip.GetFilename() },
+ GetOdexDir() + "/output_apk.odex",
+ CompilerFilter::kQuicken,
+ &error_msg,
+ { "--compact-dex-level=fast" });
+ ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) != 0) << status << " " << output_;
+
+ status = GenerateOdexForTestWithStatus(
+ { invalid_dex.GetFilename() },
+ GetOdexDir() + "/output.odex",
+ CompilerFilter::kQuicken,
+ &error_msg,
+ { "--compact-dex-level=fast" });
+ ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) != 0) << status << " " << output_;
+}
+
} // namespace art
diff --git a/libdexfile/dex/dex_file_loader.cc b/libdexfile/dex/dex_file_loader.cc
index 758a2f0..1e0f5ac 100644
--- a/libdexfile/dex/dex_file_loader.cc
+++ b/libdexfile/dex/dex_file_loader.cc
@@ -348,6 +348,8 @@
location_checksum,
oat_dex_file,
std::move(container)));
+ // Disable verification for CompactDex input.
+ verify = false;
} else {
*error_msg = "Invalid or truncated dex file";
}
diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc
index 07b1529..de67871 100644
--- a/openjdkjvmti/events.cc
+++ b/openjdkjvmti/events.cc
@@ -940,9 +940,6 @@
}
art::ScopedThreadStateChange stsc(art::Thread::Current(), art::ThreadState::kNative);
art::instrumentation::Instrumentation* instr = art::Runtime::Current()->GetInstrumentation();
- art::gc::ScopedGCCriticalSection gcs(art::Thread::Current(),
- art::gc::kGcCauseInstrumentation,
- art::gc::kCollectorTypeInstrumentation);
art::ScopedSuspendAll ssa("jvmti method tracing installation");
if (enable) {
instr->AddListener(listener, new_events);
diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc
index 83d64ef..bf2e6cd 100644
--- a/openjdkjvmti/ti_method.cc
+++ b/openjdkjvmti/ti_method.cc
@@ -42,6 +42,7 @@
#include "dex/dex_file_types.h"
#include "dex/modifiers.h"
#include "events-inl.h"
+#include "gc_root-inl.h"
#include "jit/jit.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
@@ -546,13 +547,12 @@
class CommonLocalVariableClosure : public art::Closure {
public:
- CommonLocalVariableClosure(art::Thread* caller,
- jint depth,
- jint slot)
- : result_(ERR(INTERNAL)), caller_(caller), depth_(depth), slot_(slot) {}
+ CommonLocalVariableClosure(jint depth, jint slot)
+ : result_(ERR(INTERNAL)), depth_(depth), slot_(slot) {}
void Run(art::Thread* self) OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
+ art::ScopedAssertNoThreadSuspension sants("CommonLocalVariableClosure::Run");
std::unique_ptr<art::Context> context(art::Context::Create());
FindFrameAtDepthVisitor visitor(self, context.get(), depth_);
visitor.WalkStack();
@@ -597,17 +597,17 @@
}
}
- jvmtiError GetResult() const {
+ virtual jvmtiError GetResult() {
return result_;
}
protected:
virtual jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
- REQUIRES(art::Locks::mutator_lock_) = 0;
+ REQUIRES_SHARED(art::Locks::mutator_lock_) = 0;
virtual jvmtiError GetTypeError(art::ArtMethod* method,
art::Primitive::Type type,
const std::string& descriptor)
- REQUIRES(art::Locks::mutator_lock_) = 0;
+ REQUIRES_SHARED(art::Locks::mutator_lock_) = 0;
jvmtiError GetSlotType(art::ArtMethod* method,
uint32_t dex_pc,
@@ -674,25 +674,35 @@
}
jvmtiError result_;
- art::Thread* caller_;
jint depth_;
jint slot_;
};
class GetLocalVariableClosure : public CommonLocalVariableClosure {
public:
- GetLocalVariableClosure(art::Thread* caller,
- jint depth,
+ GetLocalVariableClosure(jint depth,
jint slot,
art::Primitive::Type type,
jvalue* val)
- : CommonLocalVariableClosure(caller, depth, slot), type_(type), val_(val) {}
+ : CommonLocalVariableClosure(depth, slot),
+ type_(type),
+ val_(val),
+ obj_val_(nullptr) {}
+
+ virtual jvmtiError GetResult() REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ if (result_ == OK && type_ == art::Primitive::kPrimNot) {
+ val_->l = obj_val_.IsNull()
+ ? nullptr
+ : art::Thread::Current()->GetJniEnv()->AddLocalReference<jobject>(obj_val_.Read());
+ }
+ return CommonLocalVariableClosure::GetResult();
+ }
protected:
jvmtiError GetTypeError(art::ArtMethod* method ATTRIBUTE_UNUSED,
art::Primitive::Type slot_type,
const std::string& descriptor ATTRIBUTE_UNUSED)
- OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
switch (slot_type) {
case art::Primitive::kPrimByte:
case art::Primitive::kPrimChar:
@@ -712,7 +722,7 @@
}
jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
- OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
switch (type_) {
case art::Primitive::kPrimNot: {
uint32_t ptr_val;
@@ -722,8 +732,8 @@
&ptr_val)) {
return ERR(OPAQUE_FRAME);
}
- art::ObjPtr<art::mirror::Object> obj(reinterpret_cast<art::mirror::Object*>(ptr_val));
- val_->l = obj.IsNull() ? nullptr : caller_->GetJniEnv()->AddLocalReference<jobject>(obj);
+ obj_val_ = art::GcRoot<art::mirror::Object>(
+ reinterpret_cast<art::mirror::Object*>(ptr_val));
break;
}
case art::Primitive::kPrimInt:
@@ -760,6 +770,7 @@
private:
art::Primitive::Type type_;
jvalue* val_;
+ art::GcRoot<art::mirror::Object> obj_val_;
};
jvmtiError MethodUtil::GetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED,
@@ -782,9 +793,12 @@
art::Locks::thread_list_lock_->ExclusiveUnlock(self);
return err;
}
- GetLocalVariableClosure c(self, depth, slot, type, val);
- // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
- if (!ThreadUtil::RequestGCSafeSynchronousCheckpoint(target, &c)) {
+ art::ScopedAssertNoThreadSuspension sants("Performing GetLocalVariable");
+ GetLocalVariableClosure c(depth, slot, type, val);
+ // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution. We
+ // need to avoid suspending as we wait for the checkpoint to occur since we are (potentially)
+ // transfering a GcRoot across threads.
+ if (!target->RequestSynchronousCheckpoint(&c, art::ThreadState::kRunnable)) {
return ERR(THREAD_NOT_ALIVE);
} else {
return c.GetResult();
@@ -798,13 +812,13 @@
jint slot,
art::Primitive::Type type,
jvalue val)
- : CommonLocalVariableClosure(caller, depth, slot), type_(type), val_(val) {}
+ : CommonLocalVariableClosure(depth, slot), caller_(caller), type_(type), val_(val) {}
protected:
jvmtiError GetTypeError(art::ArtMethod* method,
art::Primitive::Type slot_type,
const std::string& descriptor)
- OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
switch (slot_type) {
case art::Primitive::kPrimNot: {
if (type_ != art::Primitive::kPrimNot) {
@@ -840,7 +854,7 @@
}
jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
- OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
switch (type_) {
case art::Primitive::kPrimNot: {
uint32_t ptr_val;
@@ -887,6 +901,7 @@
}
private:
+ art::Thread* caller_;
art::Primitive::Type type_;
jvalue val_;
};
@@ -913,7 +928,7 @@
}
SetLocalVariableClosure c(self, depth, slot, type, val);
// RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
- if (!ThreadUtil::RequestGCSafeSynchronousCheckpoint(target, &c)) {
+ if (!target->RequestSynchronousCheckpoint(&c)) {
return ERR(THREAD_NOT_ALIVE);
} else {
return c.GetResult();
@@ -922,13 +937,13 @@
class GetLocalInstanceClosure : public art::Closure {
public:
- GetLocalInstanceClosure(art::Thread* caller, jint depth, jobject* val)
+ explicit GetLocalInstanceClosure(jint depth)
: result_(ERR(INTERNAL)),
- caller_(caller),
depth_(depth),
- val_(val) {}
+ val_(nullptr) {}
void Run(art::Thread* self) OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
+ art::ScopedAssertNoThreadSuspension sants("GetLocalInstanceClosure::Run");
art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
std::unique_ptr<art::Context> context(art::Context::Create());
FindFrameAtDepthVisitor visitor(self, context.get(), depth_);
@@ -939,19 +954,22 @@
return;
}
result_ = OK;
- art::ObjPtr<art::mirror::Object> obj = visitor.GetThisObject();
- *val_ = obj.IsNull() ? nullptr : caller_->GetJniEnv()->AddLocalReference<jobject>(obj);
+ val_ = art::GcRoot<art::mirror::Object>(visitor.GetThisObject());
}
- jvmtiError GetResult() const {
+ jvmtiError GetResult(jobject* data_out) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ if (result_ == OK) {
+ *data_out = val_.IsNull()
+ ? nullptr
+ : art::Thread::Current()->GetJniEnv()->AddLocalReference<jobject>(val_.Read());
+ }
return result_;
}
private:
jvmtiError result_;
- art::Thread* caller_;
jint depth_;
- jobject* val_;
+ art::GcRoot<art::mirror::Object> val_;
};
jvmtiError MethodUtil::GetLocalInstance(jvmtiEnv* env ATTRIBUTE_UNUSED,
@@ -970,12 +988,15 @@
art::Locks::thread_list_lock_->ExclusiveUnlock(self);
return err;
}
- GetLocalInstanceClosure c(self, depth, data);
- // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
- if (!ThreadUtil::RequestGCSafeSynchronousCheckpoint(target, &c)) {
+ art::ScopedAssertNoThreadSuspension sants("Performing GetLocalInstance");
+ GetLocalInstanceClosure c(depth);
+ // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution. We
+ // need to avoid suspending as we wait for the checkpoint to occur since we are (potentially)
+ // transfering a GcRoot across threads.
+ if (!target->RequestSynchronousCheckpoint(&c, art::ThreadState::kRunnable)) {
return ERR(THREAD_NOT_ALIVE);
} else {
- return c.GetResult();
+ return c.GetResult(data);
}
}
diff --git a/openjdkjvmti/ti_monitor.cc b/openjdkjvmti/ti_monitor.cc
index 94408ba..1cfc64a 100644
--- a/openjdkjvmti/ti_monitor.cc
+++ b/openjdkjvmti/ti_monitor.cc
@@ -37,6 +37,7 @@
#include <mutex>
#include "art_jvmti.h"
+#include "gc_root-inl.h"
#include "monitor.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
@@ -351,19 +352,17 @@
}
struct GetContendedMonitorClosure : public art::Closure {
public:
- explicit GetContendedMonitorClosure(art::Thread* current, jobject* out)
- : result_thread_(current), out_(out) {}
+ GetContendedMonitorClosure() : out_(nullptr) {}
void Run(art::Thread* target_thread) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ art::ScopedAssertNoThreadSuspension sants("GetContendedMonitorClosure::Run");
switch (target_thread->GetState()) {
// These three we are actually currently waiting on a monitor and have sent the appropriate
// events (if anyone is listening).
case art::kBlocked:
case art::kTimedWaiting:
case art::kWaiting: {
- art::mirror::Object* mon = art::Monitor::GetContendedMonitor(target_thread);
- *out_ = (mon == nullptr) ? nullptr
- : result_thread_->GetJniEnv()->AddLocalReference<jobject>(mon);
+ out_ = art::GcRoot<art::mirror::Object>(art::Monitor::GetContendedMonitor(target_thread));
return;
}
case art::kTerminated:
@@ -390,22 +389,30 @@
case art::kStarting:
case art::kNative:
case art::kSuspended: {
- // We aren't currently (explicitly) waiting for a monitor anything so just return null.
- *out_ = nullptr;
+ // We aren't currently (explicitly) waiting for a monitor so just return null.
return;
}
}
}
+ jobject GetResult() REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ return out_.IsNull()
+ ? nullptr
+ : art::Thread::Current()->GetJniEnv()->AddLocalReference<jobject>(out_.Read());
+ }
+
private:
- art::Thread* result_thread_;
- jobject* out_;
+ art::GcRoot<art::mirror::Object> out_;
};
- GetContendedMonitorClosure closure(self, monitor);
- // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
- if (!ThreadUtil::RequestGCSafeSynchronousCheckpoint(target, &closure)) {
+ art::ScopedAssertNoThreadSuspension sants("Performing GetCurrentContendedMonitor");
+ GetContendedMonitorClosure closure;
+ // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution. We
+ // need to avoid suspending as we wait for the checkpoint to occur since we are (potentially)
+ // transfering a GcRoot across threads.
+ if (!target->RequestSynchronousCheckpoint(&closure, art::ThreadState::kRunnable)) {
return ERR(THREAD_NOT_ALIVE);
}
+ *monitor = closure.GetResult();
return OK;
}
diff --git a/openjdkjvmti/ti_stack.cc b/openjdkjvmti/ti_stack.cc
index 373944f..41a649b 100644
--- a/openjdkjvmti/ti_stack.cc
+++ b/openjdkjvmti/ti_stack.cc
@@ -258,7 +258,7 @@
static_cast<size_t>(start_depth),
static_cast<size_t>(max_frame_count));
// RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
- if (!ThreadUtil::RequestGCSafeSynchronousCheckpoint(thread, &closure)) {
+ if (!thread->RequestSynchronousCheckpoint(&closure)) {
return ERR(THREAD_NOT_ALIVE);
}
*count_ptr = static_cast<jint>(closure.index);
@@ -269,7 +269,7 @@
} else {
GetStackTraceVectorClosure closure(0, 0);
// RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
- if (!ThreadUtil::RequestGCSafeSynchronousCheckpoint(thread, &closure)) {
+ if (!thread->RequestSynchronousCheckpoint(&closure)) {
return ERR(THREAD_NOT_ALIVE);
}
@@ -484,7 +484,7 @@
*stack_info_ptr = nullptr;
return ERR(NONE);
}
- if (stack_info_ptr == nullptr || stack_info_ptr == nullptr) {
+ if (thread_list == nullptr || stack_info_ptr == nullptr) {
return ERR(NULL_POINTER);
}
@@ -713,7 +713,7 @@
GetFrameCountClosure closure;
// RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
- if (!ThreadUtil::RequestGCSafeSynchronousCheckpoint(thread, &closure)) {
+ if (!thread->RequestSynchronousCheckpoint(&closure)) {
return ERR(THREAD_NOT_ALIVE);
}
@@ -803,7 +803,7 @@
GetLocationClosure closure(static_cast<size_t>(depth));
// RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
- if (!ThreadUtil::RequestGCSafeSynchronousCheckpoint(thread, &closure)) {
+ if (!thread->RequestSynchronousCheckpoint(&closure)) {
return ERR(THREAD_NOT_ALIVE);
}
@@ -882,8 +882,8 @@
template<typename Fn>
struct MonitorInfoClosure : public art::Closure {
public:
- MonitorInfoClosure(art::ScopedObjectAccess& soa, Fn handle_results)
- : soa_(soa), err_(OK), handle_results_(handle_results) {}
+ explicit MonitorInfoClosure(Fn handle_results)
+ : err_(OK), handle_results_(handle_results) {}
void Run(art::Thread* target) OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
@@ -893,7 +893,7 @@
// Find any other monitors, including ones acquired in native code.
art::RootInfo root_info(art::kRootVMInternal);
target->GetJniEnv()->VisitMonitorRoots(&visitor, root_info);
- err_ = handle_results_(soa_, visitor);
+ err_ = handle_results_(visitor);
}
jvmtiError GetError() {
@@ -901,17 +901,18 @@
}
private:
- art::ScopedObjectAccess& soa_;
jvmtiError err_;
Fn handle_results_;
};
template <typename Fn>
-static jvmtiError GetOwnedMonitorInfoCommon(jthread thread, Fn handle_results) {
+static jvmtiError GetOwnedMonitorInfoCommon(const art::ScopedObjectAccessAlreadyRunnable& soa,
+ jthread thread,
+ Fn handle_results)
+ REQUIRES_SHARED(art::Locks::mutator_lock_) {
art::Thread* self = art::Thread::Current();
- art::ScopedObjectAccess soa(self);
- MonitorInfoClosure<Fn> closure(soa, handle_results);
+ MonitorInfoClosure<Fn> closure(handle_results);
bool called_method = false;
{
art::Locks::thread_list_lock_->ExclusiveLock(self);
@@ -924,7 +925,7 @@
if (target != self) {
called_method = true;
// RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
- if (!ThreadUtil::RequestGCSafeSynchronousCheckpoint(target, &closure)) {
+ if (!target->RequestSynchronousCheckpoint(&closure)) {
return ERR(THREAD_NOT_ALIVE);
}
} else {
@@ -948,47 +949,64 @@
if (info_cnt == nullptr || info_ptr == nullptr) {
return ERR(NULL_POINTER);
}
- auto handle_fun = [&] (art::ScopedObjectAccess& soa, MonitorVisitor& visitor)
- REQUIRES_SHARED(art::Locks::mutator_lock_) {
- auto nbytes = sizeof(jvmtiMonitorStackDepthInfo) * visitor.monitors.size();
- jvmtiError err = env->Allocate(nbytes, reinterpret_cast<unsigned char**>(info_ptr));
- if (err != OK) {
- return err;
- }
- *info_cnt = visitor.monitors.size();
+ art::ScopedObjectAccess soa(art::Thread::Current());
+ std::vector<art::GcRoot<art::mirror::Object>> mons;
+ std::vector<uint32_t> depths;
+ auto handle_fun = [&] (MonitorVisitor& visitor) REQUIRES_SHARED(art::Locks::mutator_lock_) {
for (size_t i = 0; i < visitor.monitors.size(); i++) {
- (*info_ptr)[i] = {
- soa.Env()->AddLocalReference<jobject>(visitor.monitors[i].Get()),
- visitor.stack_depths[i]
- };
+ mons.push_back(art::GcRoot<art::mirror::Object>(visitor.monitors[i].Get()));
+ depths.push_back(visitor.stack_depths[i]);
}
return OK;
};
- return GetOwnedMonitorInfoCommon(thread, handle_fun);
+ jvmtiError err = GetOwnedMonitorInfoCommon(soa, thread, handle_fun);
+ if (err != OK) {
+ return err;
+ }
+ auto nbytes = sizeof(jvmtiMonitorStackDepthInfo) * mons.size();
+ err = env->Allocate(nbytes, reinterpret_cast<unsigned char**>(info_ptr));
+ if (err != OK) {
+ return err;
+ }
+ *info_cnt = mons.size();
+ for (uint32_t i = 0; i < mons.size(); i++) {
+ (*info_ptr)[i] = {
+ soa.AddLocalReference<jobject>(mons[i].Read()),
+ static_cast<jint>(depths[i])
+ };
+ }
+ return err;
}
jvmtiError StackUtil::GetOwnedMonitorInfo(jvmtiEnv* env,
jthread thread,
jint* owned_monitor_count_ptr,
jobject** owned_monitors_ptr) {
- if (owned_monitors_ptr == nullptr || owned_monitors_ptr == nullptr) {
+ if (owned_monitor_count_ptr == nullptr || owned_monitors_ptr == nullptr) {
return ERR(NULL_POINTER);
}
- auto handle_fun = [&] (art::ScopedObjectAccess& soa, MonitorVisitor& visitor)
- REQUIRES_SHARED(art::Locks::mutator_lock_) {
- auto nbytes = sizeof(jobject) * visitor.monitors.size();
- jvmtiError err = env->Allocate(nbytes, reinterpret_cast<unsigned char**>(owned_monitors_ptr));
- if (err != OK) {
- return err;
- }
- *owned_monitor_count_ptr = visitor.monitors.size();
+ art::ScopedObjectAccess soa(art::Thread::Current());
+ std::vector<art::GcRoot<art::mirror::Object>> mons;
+ auto handle_fun = [&] (MonitorVisitor& visitor) REQUIRES_SHARED(art::Locks::mutator_lock_) {
for (size_t i = 0; i < visitor.monitors.size(); i++) {
- (*owned_monitors_ptr)[i] =
- soa.Env()->AddLocalReference<jobject>(visitor.monitors[i].Get());
+ mons.push_back(art::GcRoot<art::mirror::Object>(visitor.monitors[i].Get()));
}
return OK;
};
- return GetOwnedMonitorInfoCommon(thread, handle_fun);
+ jvmtiError err = GetOwnedMonitorInfoCommon(soa, thread, handle_fun);
+ if (err != OK) {
+ return err;
+ }
+ auto nbytes = sizeof(jobject) * mons.size();
+ err = env->Allocate(nbytes, reinterpret_cast<unsigned char**>(owned_monitors_ptr));
+ if (err != OK) {
+ return err;
+ }
+ *owned_monitor_count_ptr = mons.size();
+ for (uint32_t i = 0; i < mons.size(); i++) {
+ (*owned_monitors_ptr)[i] = soa.AddLocalReference<jobject>(mons[i].Read());
+ }
+ return err;
}
jvmtiError StackUtil::NotifyFramePop(jvmtiEnv* env, jthread thread, jint depth) {
diff --git a/openjdkjvmti/ti_thread.cc b/openjdkjvmti/ti_thread.cc
index 555c5a7..414139c 100644
--- a/openjdkjvmti/ti_thread.cc
+++ b/openjdkjvmti/ti_thread.cc
@@ -1077,7 +1077,7 @@
};
StopThreadClosure c(exc);
// RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
- if (RequestGCSafeSynchronousCheckpoint(target, &c)) {
+ if (target->RequestSynchronousCheckpoint(&c)) {
return OK;
} else {
// Something went wrong, probably the thread died.
@@ -1100,29 +1100,4 @@
return OK;
}
-class GcCriticalSectionClosure : public art::Closure {
- public:
- explicit GcCriticalSectionClosure(art::Closure* wrapped) : wrapped_(wrapped) {}
-
- void Run(art::Thread* self) OVERRIDE {
- if (art::kIsDebugBuild) {
- art::Locks::thread_list_lock_->AssertNotHeld(art::Thread::Current());
- }
- // This might block as it waits for any in-progress GCs to finish but this is fine since we
- // released the Thread-list-lock prior to calling this in RequestSynchronousCheckpoint.
- art::gc::ScopedGCCriticalSection sgccs(art::Thread::Current(),
- art::gc::kGcCauseDebugger,
- art::gc::kCollectorTypeDebugger);
- wrapped_->Run(self);
- }
-
- private:
- art::Closure* wrapped_;
-};
-
-bool ThreadUtil::RequestGCSafeSynchronousCheckpoint(art::Thread* thr, art::Closure* function) {
- GcCriticalSectionClosure gccsc(function);
- return thr->RequestSynchronousCheckpoint(&gccsc);
-}
-
} // namespace openjdkjvmti
diff --git a/openjdkjvmti/ti_thread.h b/openjdkjvmti/ti_thread.h
index 341bffe..c6b6af1 100644
--- a/openjdkjvmti/ti_thread.h
+++ b/openjdkjvmti/ti_thread.h
@@ -134,16 +134,6 @@
REQUIRES(!art::Locks::user_code_suspension_lock_,
!art::Locks::thread_suspend_count_lock_);
- // This will request a synchronous checkpoint in such a way as to prevent gc races if a local
- // variable is taken from one thread's stack and placed in the stack of another thread.
- // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution. This is
- // due to the fact that Thread::Current() needs to go to sleep to allow the targeted thread to
- // execute the checkpoint for us if it is Runnable.
- static bool RequestGCSafeSynchronousCheckpoint(art::Thread* thr, art::Closure* function)
- REQUIRES_SHARED(art::Locks::mutator_lock_)
- RELEASE(art::Locks::thread_list_lock_)
- REQUIRES(!art::Locks::thread_suspend_count_lock_);
-
private:
// We need to make sure only one thread tries to suspend threads at a time so we can get the
// 'suspend-only-once' behavior the spec requires. Internally, ART considers suspension to be a
diff --git a/runtime/barrier.cc b/runtime/barrier.cc
index 4329a5a..8d3cf45 100644
--- a/runtime/barrier.cc
+++ b/runtime/barrier.cc
@@ -31,6 +31,9 @@
condition_("GC barrier condition", lock_) {
}
+template void Barrier::Increment<Barrier::kAllowHoldingLocks>(Thread* self, int delta);
+template void Barrier::Increment<Barrier::kDisallowHoldingLocks>(Thread* self, int delta);
+
void Barrier::Pass(Thread* self) {
MutexLock mu(self, lock_);
SetCountLocked(self, count_ - 1);
@@ -45,6 +48,7 @@
SetCountLocked(self, count);
}
+template <Barrier::LockHandling locks>
void Barrier::Increment(Thread* self, int delta) {
MutexLock mu(self, lock_);
SetCountLocked(self, count_ + delta);
@@ -57,7 +61,11 @@
// be decremented to zero and a Broadcast will be made on the
// condition variable, thus waking this up.
while (count_ != 0) {
- condition_.Wait(self);
+ if (locks == kAllowHoldingLocks) {
+ condition_.WaitHoldingLocks(self);
+ } else {
+ condition_.Wait(self);
+ }
}
}
diff --git a/runtime/barrier.h b/runtime/barrier.h
index d7c4661..8a38c4c 100644
--- a/runtime/barrier.h
+++ b/runtime/barrier.h
@@ -35,6 +35,11 @@
// TODO: Maybe give this a better name.
class Barrier {
public:
+ enum LockHandling {
+ kAllowHoldingLocks,
+ kDisallowHoldingLocks,
+ };
+
explicit Barrier(int count);
virtual ~Barrier();
@@ -50,7 +55,9 @@
// If these calls are made in that situation, the offending thread is likely to go back
// to sleep, resulting in a deadlock.
- // Increment the count by delta, wait on condition if count is non zero.
+ // Increment the count by delta, wait on condition if count is non zero. If LockHandling is
+ // kAllowHoldingLocks we will not check that all locks are released when waiting.
+ template <Barrier::LockHandling locks = kDisallowHoldingLocks>
void Increment(Thread* self, int delta) REQUIRES(!lock_);
// Increment the count by delta, wait on condition if count is non zero, with a timeout. Returns
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 8a29ff3..1d72b46 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -5863,14 +5863,6 @@
// smaller as we go on.
uint32_t hash_index = hash_table.FindAndRemove(&super_method_name_comparator);
if (hash_index != hash_table.GetNotFoundIndex()) {
- // Run a check whether we are going to override a method which is hidden
- // to `klass`, but ignore the result as we only warn at the moment.
- // We cannot do this test earlier because we need to establish that
- // a method is being overridden first. ShouldBlockAccessToMember would
- // print bogus warnings otherwise.
- hiddenapi::ShouldBlockAccessToMember(
- super_method, klass->GetClassLoader(), hiddenapi::kOverride);
-
ArtMethod* virtual_method = klass->GetVirtualMethodDuringLinking(
hash_index, image_pointer_size_);
if (super_method->IsFinal()) {
diff --git a/runtime/dex/art_dex_file_loader.cc b/runtime/dex/art_dex_file_loader.cc
index c456764..9802c69 100644
--- a/runtime/dex/art_dex_file_loader.cc
+++ b/runtime/dex/art_dex_file_loader.cc
@@ -205,6 +205,12 @@
error_msg,
std::make_unique<MemMapContainer>(std::move(map)),
/*verify_result*/ nullptr);
+ // Opening CompactDex is only supported from vdex files.
+ if (dex_file != nullptr && dex_file->IsCompactDexFile()) {
+ *error_msg = StringPrintf("Opening CompactDex file '%s' is only supported from vdex files",
+ location.c_str());
+ return nullptr;
+ }
return dex_file;
}
@@ -329,6 +335,12 @@
std::make_unique<MemMapContainer>(std::move(map)),
/*verify_result*/ nullptr);
+ // Opening CompactDex is only supported from vdex files.
+ if (dex_file != nullptr && dex_file->IsCompactDexFile()) {
+ *error_msg = StringPrintf("Opening CompactDex file '%s' is only supported from vdex files",
+ location.c_str());
+ return nullptr;
+ }
return dex_file;
}
@@ -397,6 +409,11 @@
error_msg,
std::make_unique<MemMapContainer>(std::move(map)),
&verify_result);
+ if (dex_file != nullptr && dex_file->IsCompactDexFile()) {
+ *error_msg = StringPrintf("Opening CompactDex file '%s' is only supported from vdex files",
+ location.c_str());
+ return nullptr;
+ }
if (dex_file == nullptr) {
if (verify_result == VerifyResult::kVerifyNotAttempted) {
*error_code = ZipOpenErrorCode::kDexFileError;
diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h
index f2ea2fd..5c6b4b5 100644
--- a/runtime/hidden_api.h
+++ b/runtime/hidden_api.h
@@ -27,6 +27,23 @@
namespace art {
namespace hiddenapi {
+// Hidden API enforcement policy
+// This must be kept in sync with ApplicationInfo.ApiEnforcementPolicy in
+// frameworks/base/core/java/android/content/pm/ApplicationInfo.java
+enum class EnforcementPolicy {
+ kNoChecks = 0,
+ kAllLists = 1, // ban anything but whitelist
+ kDarkGreyAndBlackList = 2, // ban dark grey & blacklist
+ kBlacklistOnly = 3, // ban blacklist violations only
+ kMax = kBlacklistOnly,
+};
+
+inline EnforcementPolicy EnforcementPolicyFromInt(int api_policy_int) {
+ DCHECK_GE(api_policy_int, 0);
+ DCHECK_LE(api_policy_int, static_cast<int>(EnforcementPolicy::kMax));
+ return static_cast<EnforcementPolicy>(api_policy_int);
+}
+
enum Action {
kAllow,
kAllowButWarn,
@@ -38,7 +55,6 @@
kReflection,
kJNI,
kLinking,
- kOverride,
};
inline std::ostream& operator<<(std::ostream& os, AccessMethod value) {
@@ -52,23 +68,42 @@
case kLinking:
os << "linking";
break;
- case kOverride:
- os << "override";
- break;
}
return os;
}
+static constexpr bool EnumsEqual(EnforcementPolicy policy, HiddenApiAccessFlags::ApiList apiList) {
+ return static_cast<int>(policy) == static_cast<int>(apiList);
+}
+
inline Action GetMemberAction(uint32_t access_flags) {
- switch (HiddenApiAccessFlags::DecodeFromRuntime(access_flags)) {
- case HiddenApiAccessFlags::kWhitelist:
- return kAllow;
- case HiddenApiAccessFlags::kLightGreylist:
- return kAllowButWarn;
- case HiddenApiAccessFlags::kDarkGreylist:
- return kAllowButWarnAndToast;
- case HiddenApiAccessFlags::kBlacklist:
- return kDeny;
+ EnforcementPolicy policy = Runtime::Current()->GetHiddenApiEnforcementPolicy();
+ if (policy == EnforcementPolicy::kNoChecks) {
+ // Exit early. Nothing to enforce.
+ return kAllow;
+ }
+
+ HiddenApiAccessFlags::ApiList api_list = HiddenApiAccessFlags::DecodeFromRuntime(access_flags);
+ if (api_list == HiddenApiAccessFlags::kWhitelist) {
+ return kAllow;
+ }
+ // The logic below relies on equality of values in the enums EnforcementPolicy and
+ // HiddenApiAccessFlags::ApiList, and their ordering. Assert that this is as expected.
+ static_assert(
+ EnumsEqual(EnforcementPolicy::kAllLists, HiddenApiAccessFlags::kLightGreylist) &&
+ EnumsEqual(EnforcementPolicy::kDarkGreyAndBlackList, HiddenApiAccessFlags::kDarkGreylist) &&
+ EnumsEqual(EnforcementPolicy::kBlacklistOnly, HiddenApiAccessFlags::kBlacklist),
+ "Mismatch between EnforcementPolicy and ApiList enums");
+ static_assert(
+ EnforcementPolicy::kAllLists < EnforcementPolicy::kDarkGreyAndBlackList &&
+ EnforcementPolicy::kDarkGreyAndBlackList < EnforcementPolicy::kBlacklistOnly,
+ "EnforcementPolicy values ordering not correct");
+ if (static_cast<int>(policy) > static_cast<int>(api_list)) {
+ return api_list == HiddenApiAccessFlags::kDarkGreylist
+ ? kAllowButWarnAndToast
+ : kAllowButWarn;
+ } else {
+ return kDeny;
}
}
@@ -107,12 +142,6 @@
AccessMethod access_method)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(member != nullptr);
- Runtime* runtime = Runtime::Current();
-
- if (!runtime->AreHiddenApiChecksEnabled()) {
- // Exit early. Nothing to enforce.
- return false;
- }
Action action = GetMemberAction(member->GetAccessFlags());
if (action == kAllow) {
@@ -133,14 +162,16 @@
// We do this regardless of whether we block the access or not.
WarnAboutMemberAccess(member, access_method);
- // Block access if on blacklist.
if (action == kDeny) {
+ // Block access
return true;
}
// Allow access to this member but print a warning.
DCHECK(action == kAllowButWarn || action == kAllowButWarnAndToast);
+ Runtime* runtime = Runtime::Current();
+
// Depending on a runtime flag, we might move the member into whitelist and
// skip the warning the next time the member is accessed.
if (runtime->ShouldDedupeHiddenApiWarnings()) {
@@ -150,7 +181,7 @@
// If this action requires a UI warning, set the appropriate flag.
if (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag()) {
- Runtime::Current()->SetPendingHiddenApiWarning(true);
+ runtime->SetPendingHiddenApiWarning(true);
}
return false;
diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
index fc94266..3692a30 100644
--- a/runtime/native/dalvik_system_VMDebug.cc
+++ b/runtime/native/dalvik_system_VMDebug.cc
@@ -89,17 +89,27 @@
static void VMDebug_startMethodTracingDdmsImpl(JNIEnv*, jclass, jint bufferSize, jint flags,
jboolean samplingEnabled, jint intervalUs) {
- Trace::Start("[DDMS]", -1, bufferSize, flags, Trace::TraceOutputMode::kDDMS,
- samplingEnabled ? Trace::TraceMode::kSampling : Trace::TraceMode::kMethodTracing,
- intervalUs);
+ Trace::StartDDMS(bufferSize,
+ flags,
+ samplingEnabled ? Trace::TraceMode::kSampling : Trace::TraceMode::kMethodTracing,
+ intervalUs);
}
-static void VMDebug_startMethodTracingFd(JNIEnv* env, jclass, jstring javaTraceFilename,
- jint javaFd, jint bufferSize, jint flags,
- jboolean samplingEnabled, jint intervalUs,
+static void VMDebug_startMethodTracingFd(JNIEnv* env,
+ jclass,
+ jstring javaTraceFilename ATTRIBUTE_UNUSED,
+ jint javaFd,
+ jint bufferSize,
+ jint flags,
+ jboolean samplingEnabled,
+ jint intervalUs,
jboolean streamingOutput) {
int originalFd = javaFd;
if (originalFd < 0) {
+ ScopedObjectAccess soa(env);
+ soa.Self()->ThrowNewExceptionF("Ljava/lang/RuntimeException;",
+ "Trace fd is invalid: %d",
+ originalFd);
return;
}
@@ -107,18 +117,20 @@
if (fd < 0) {
ScopedObjectAccess soa(env);
soa.Self()->ThrowNewExceptionF("Ljava/lang/RuntimeException;",
- "dup(%d) failed: %s", originalFd, strerror(errno));
+ "dup(%d) failed: %s",
+ originalFd,
+ strerror(errno));
return;
}
- ScopedUtfChars traceFilename(env, javaTraceFilename);
- if (traceFilename.c_str() == nullptr) {
- return;
- }
+ // Ignore the traceFilename.
Trace::TraceOutputMode outputMode = streamingOutput
? Trace::TraceOutputMode::kStreaming
: Trace::TraceOutputMode::kFile;
- Trace::Start(traceFilename.c_str(), fd, bufferSize, flags, outputMode,
+ Trace::Start(fd,
+ bufferSize,
+ flags,
+ outputMode,
samplingEnabled ? Trace::TraceMode::kSampling : Trace::TraceMode::kMethodTracing,
intervalUs);
}
@@ -130,7 +142,10 @@
if (traceFilename.c_str() == nullptr) {
return;
}
- Trace::Start(traceFilename.c_str(), -1, bufferSize, flags, Trace::TraceOutputMode::kFile,
+ Trace::Start(traceFilename.c_str(),
+ bufferSize,
+ flags,
+ Trace::TraceOutputMode::kFile,
samplingEnabled ? Trace::TraceMode::kSampling : Trace::TraceMode::kMethodTracing,
intervalUs);
}
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index 8913569..d9a5096 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -162,19 +162,24 @@
// Must match values in com.android.internal.os.Zygote.
enum {
- DEBUG_ENABLE_JDWP = 1,
- DEBUG_ENABLE_CHECKJNI = 1 << 1,
- DEBUG_ENABLE_ASSERT = 1 << 2,
- DEBUG_ENABLE_SAFEMODE = 1 << 3,
- DEBUG_ENABLE_JNI_LOGGING = 1 << 4,
- DEBUG_GENERATE_DEBUG_INFO = 1 << 5,
- DEBUG_ALWAYS_JIT = 1 << 6,
- DEBUG_NATIVE_DEBUGGABLE = 1 << 7,
- DEBUG_JAVA_DEBUGGABLE = 1 << 8,
- DISABLE_VERIFIER = 1 << 9,
- ONLY_USE_SYSTEM_OAT_FILES = 1 << 10,
- ENABLE_HIDDEN_API_CHECKS = 1 << 11,
- DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 12,
+ DEBUG_ENABLE_JDWP = 1,
+ DEBUG_ENABLE_CHECKJNI = 1 << 1,
+ DEBUG_ENABLE_ASSERT = 1 << 2,
+ DEBUG_ENABLE_SAFEMODE = 1 << 3,
+ DEBUG_ENABLE_JNI_LOGGING = 1 << 4,
+ DEBUG_GENERATE_DEBUG_INFO = 1 << 5,
+ DEBUG_ALWAYS_JIT = 1 << 6,
+ DEBUG_NATIVE_DEBUGGABLE = 1 << 7,
+ DEBUG_JAVA_DEBUGGABLE = 1 << 8,
+ DISABLE_VERIFIER = 1 << 9,
+ ONLY_USE_SYSTEM_OAT_FILES = 1 << 10,
+ DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 11,
+ HIDDEN_API_ENFORCEMENT_POLICY_MASK = (1 << 12)
+ | (1 << 13),
+
+ // bits to shift (flags & HIDDEN_API_ENFORCEMENT_POLICY_MASK) by to get a value
+ // corresponding to hiddenapi::EnforcementPolicy
+ API_ENFORCEMENT_POLICY_SHIFT = CTZ(HIDDEN_API_ENFORCEMENT_POLICY_MASK),
};
static uint32_t EnableDebugFeatures(uint32_t runtime_flags) {
@@ -285,7 +290,8 @@
// Our system thread ID, etc, has changed so reset Thread state.
thread->InitAfterFork();
runtime_flags = EnableDebugFeatures(runtime_flags);
- bool do_hidden_api_checks = false;
+ hiddenapi::EnforcementPolicy api_enforcement_policy = hiddenapi::EnforcementPolicy::kNoChecks;
+ bool dedupe_hidden_api_warnings = true;
if ((runtime_flags & DISABLE_VERIFIER) != 0) {
Runtime::Current()->DisableVerifier();
@@ -297,10 +303,9 @@
runtime_flags &= ~ONLY_USE_SYSTEM_OAT_FILES;
}
- if ((runtime_flags & ENABLE_HIDDEN_API_CHECKS) != 0) {
- do_hidden_api_checks = true;
- runtime_flags &= ~ENABLE_HIDDEN_API_CHECKS;
- }
+ api_enforcement_policy = hiddenapi::EnforcementPolicyFromInt(
+ (runtime_flags & HIDDEN_API_ENFORCEMENT_POLICY_MASK) >> API_ENFORCEMENT_POLICY_SHIFT);
+ runtime_flags &= ~HIDDEN_API_ENFORCEMENT_POLICY_MASK;
if (runtime_flags != 0) {
LOG(ERROR) << StringPrintf("Unknown bits set in runtime_flags: %#x", runtime_flags);
@@ -338,7 +343,6 @@
std::string trace_file = StringPrintf("/data/misc/trace/%s.trace.bin", proc_name.c_str());
Trace::Start(trace_file.c_str(),
- -1,
buffer_size,
0, // TODO: Expose flags.
output_mode,
@@ -351,11 +355,13 @@
}
}
+ bool do_hidden_api_checks = api_enforcement_policy != hiddenapi::EnforcementPolicy::kNoChecks;
DCHECK(!(is_system_server && do_hidden_api_checks))
- << "SystemServer should be forked with ENABLE_HIDDEN_API_CHECKS";
+ << "SystemServer should be forked with EnforcementPolicy::kDisable";
DCHECK(!(is_zygote && do_hidden_api_checks))
- << "Child zygote processes should be forked with ENABLE_HIDDEN_API_CHECKS";
- Runtime::Current()->SetHiddenApiChecksEnabled(do_hidden_api_checks);
+ << "Child zygote processes should be forked with EnforcementPolicy::kDisable";
+ Runtime::Current()->SetHiddenApiEnforcementPolicy(api_enforcement_policy);
+ Runtime::Current()->SetDedupeHiddenApiWarnings(dedupe_hidden_api_warnings);
// Clear the hidden API warning flag, in case it was set.
Runtime::Current()->SetPendingHiddenApiWarning(false);
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 25d5037..fc61c95 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -89,8 +89,8 @@
// access hidden APIs. This can be *very* expensive. Never call this in a loop.
ALWAYS_INLINE static bool ShouldEnforceHiddenApi(Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
- return Runtime::Current()->AreHiddenApiChecksEnabled() &&
- !IsCallerInBootClassPath(self);
+ hiddenapi::EnforcementPolicy policy = Runtime::Current()->GetHiddenApiEnforcementPolicy();
+ return policy != hiddenapi::EnforcementPolicy::kNoChecks && !IsCallerInBootClassPath(self);
}
// Returns true if the first non-ClassClass caller up the stack should not be
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 7d9d342..9a626ba 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -267,7 +267,7 @@
oat_file_manager_(nullptr),
is_low_memory_mode_(false),
safe_mode_(false),
- do_hidden_api_checks_(false),
+ hidden_api_policy_(hiddenapi::EnforcementPolicy::kNoChecks),
pending_hidden_api_warning_(false),
dedupe_hidden_api_warnings_(true),
always_set_hidden_api_warning_flag_(false),
@@ -839,7 +839,6 @@
if (trace_config_.get() != nullptr && trace_config_->trace_file != "") {
ScopedThreadStateChange tsc(self, kWaitingForMethodTracingStart);
Trace::Start(trace_config_->trace_file.c_str(),
- -1,
static_cast<int>(trace_config_->trace_file_size),
0,
trace_config_->trace_output_mode,
@@ -1196,9 +1195,14 @@
// by default and we only enable them if:
// (a) runtime was started with a flag that enables the checks, or
// (b) Zygote forked a new process that is not exempt (see ZygoteHooks).
- do_hidden_api_checks_ = runtime_options.Exists(Opt::HiddenApiChecks);
- DCHECK(!is_zygote_ || !do_hidden_api_checks_)
- << "Zygote should not be started with hidden API checks";
+ bool do_hidden_api_checks = runtime_options.Exists(Opt::HiddenApiChecks);
+ DCHECK(!is_zygote_ || !do_hidden_api_checks);
+ // TODO pass the actual enforcement policy in, rather than just a single bit.
+ // As is, we're encoding some logic here about which specific policy to use, which would be better
+ // controlled by the framework.
+ hidden_api_policy_ = do_hidden_api_checks
+ ? hiddenapi::EnforcementPolicy::kBlacklistOnly
+ : hiddenapi::EnforcementPolicy::kNoChecks;
no_sig_chain_ = runtime_options.Exists(Opt::NoSigChain);
force_native_bridge_ = runtime_options.Exists(Opt::ForceNativeBridge);
diff --git a/runtime/runtime.h b/runtime/runtime.h
index c7f650e..dba31b2 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -49,6 +49,10 @@
class Heap;
} // namespace gc
+namespace hiddenapi {
+enum class EnforcementPolicy;
+} // namespace hiddenapi
+
namespace jit {
class Jit;
class JitOptions;
@@ -520,12 +524,12 @@
bool IsVerificationEnabled() const;
bool IsVerificationSoftFail() const;
- void SetHiddenApiChecksEnabled(bool value) {
- do_hidden_api_checks_ = value;
+ void SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy policy) {
+ hidden_api_policy_ = policy;
}
- bool AreHiddenApiChecksEnabled() const {
- return do_hidden_api_checks_;
+ hiddenapi::EnforcementPolicy GetHiddenApiEnforcementPolicy() const {
+ return hidden_api_policy_;
}
void SetPendingHiddenApiWarning(bool value) {
@@ -990,7 +994,7 @@
bool safe_mode_;
// Whether access checks on hidden API should be performed.
- bool do_hidden_api_checks_;
+ hiddenapi::EnforcementPolicy hidden_api_policy_;
// Whether the application has used an API which is not restricted but we
// should issue a warning about it.
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 5b03c2d..c0deda8 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1438,8 +1438,12 @@
barrier_.Pass(self);
}
- void Wait(Thread* self) {
- barrier_.Increment(self, 1);
+ void Wait(Thread* self, ThreadState suspend_state) {
+ if (suspend_state != ThreadState::kRunnable) {
+ barrier_.Increment<Barrier::kDisallowHoldingLocks>(self, 1);
+ } else {
+ barrier_.Increment<Barrier::kAllowHoldingLocks>(self, 1);
+ }
}
private:
@@ -1448,7 +1452,7 @@
};
// RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
-bool Thread::RequestSynchronousCheckpoint(Closure* function) {
+bool Thread::RequestSynchronousCheckpoint(Closure* function, ThreadState suspend_state) {
Thread* self = Thread::Current();
if (this == Thread::Current()) {
Locks::thread_list_lock_->AssertExclusiveHeld(self);
@@ -1496,8 +1500,8 @@
// Relinquish the thread-list lock. We should not wait holding any locks. We cannot
// reacquire it since we don't know if 'this' hasn't been deleted yet.
Locks::thread_list_lock_->ExclusiveUnlock(self);
- ScopedThreadSuspension sts(self, ThreadState::kWaiting);
- barrier_closure.Wait(self);
+ ScopedThreadStateChange sts(self, suspend_state);
+ barrier_closure.Wait(self, suspend_state);
return true;
}
// Fall-through.
@@ -1521,7 +1525,7 @@
// that we can call ModifySuspendCount without racing against ThreadList::Unregister.
ScopedThreadListLockUnlock stllu(self);
{
- ScopedThreadSuspension sts(self, ThreadState::kWaiting);
+ ScopedThreadStateChange sts(self, suspend_state);
while (GetState() == ThreadState::kRunnable) {
// We became runnable again. Wait till the suspend triggered in ModifySuspendCount
// moves us to suspended.
diff --git a/runtime/thread.h b/runtime/thread.h
index 6549fc1..9adae96 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -263,16 +263,31 @@
WARN_UNUSED
REQUIRES(Locks::thread_suspend_count_lock_);
+ // Requests a checkpoint closure to run on another thread. The closure will be run when the thread
+ // gets suspended. This will return true if the closure was added and will (eventually) be
+ // executed. It returns false otherwise.
+ //
+ // Since multiple closures can be queued and some closures can delay other threads from running no
+ // closure should attempt to suspend another thread while running.
+ // TODO We should add some debug option that verifies this.
bool RequestCheckpoint(Closure* function)
REQUIRES(Locks::thread_suspend_count_lock_);
// RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution. This is
// due to the fact that Thread::Current() needs to go to sleep to allow the targeted thread to
- // execute the checkpoint for us if it is Runnable.
- bool RequestSynchronousCheckpoint(Closure* function)
+ // execute the checkpoint for us if it is Runnable. The suspend_state is the state that the thread
+ // will go into while it is awaiting the checkpoint to be run.
+ // NB Passing ThreadState::kRunnable may cause the current thread to wait in a condition variable
+ // while holding the mutator_lock_. Callers should ensure that this will not cause any problems
+ // for the closure or the rest of the system.
+ // NB Since multiple closures can be queued and some closures can delay other threads from running
+ // no closure should attempt to suspend another thread while running.
+ bool RequestSynchronousCheckpoint(Closure* function,
+ ThreadState suspend_state = ThreadState::kWaiting)
REQUIRES_SHARED(Locks::mutator_lock_)
RELEASE(Locks::thread_list_lock_)
REQUIRES(!Locks::thread_suspend_count_lock_);
+
bool RequestEmptyCheckpoint()
REQUIRES(Locks::thread_suspend_count_lock_);
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 0f321b6..91d2b37 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -319,8 +319,74 @@
return nullptr;
}
-void Trace::Start(const char* trace_filename, int trace_fd, size_t buffer_size, int flags,
- TraceOutputMode output_mode, TraceMode trace_mode, int interval_us) {
+void Trace::Start(const char* trace_filename,
+ size_t buffer_size,
+ int flags,
+ TraceOutputMode output_mode,
+ TraceMode trace_mode,
+ int interval_us) {
+ std::unique_ptr<File> file(OS::CreateEmptyFileWriteOnly(trace_filename));
+ if (file == nullptr) {
+ std::string msg = android::base::StringPrintf("Unable to open trace file '%s'", trace_filename);
+ PLOG(ERROR) << msg;
+ ScopedObjectAccess soa(Thread::Current());
+ Thread::Current()->ThrowNewException("Ljava/lang/RuntimeException;", msg.c_str());
+ return;
+ }
+ Start(std::move(file), buffer_size, flags, output_mode, trace_mode, interval_us);
+}
+
+void Trace::Start(int trace_fd,
+ size_t buffer_size,
+ int flags,
+ TraceOutputMode output_mode,
+ TraceMode trace_mode,
+ int interval_us) {
+ if (trace_fd < 0) {
+ std::string msg = android::base::StringPrintf("Unable to start tracing with invalid fd %d",
+ trace_fd);
+ LOG(ERROR) << msg;
+ ScopedObjectAccess soa(Thread::Current());
+ Thread::Current()->ThrowNewException("Ljava/lang/RuntimeException;", msg.c_str());
+ return;
+ }
+ std::unique_ptr<File> file(new File(trace_fd, "tracefile"));
+ Start(std::move(file), buffer_size, flags, output_mode, trace_mode, interval_us);
+}
+
+void Trace::StartDDMS(size_t buffer_size,
+ int flags,
+ TraceMode trace_mode,
+ int interval_us) {
+ Start(std::unique_ptr<File>(),
+ buffer_size,
+ flags,
+ TraceOutputMode::kDDMS,
+ trace_mode,
+ interval_us);
+}
+
+void Trace::Start(std::unique_ptr<File>&& trace_file_in,
+ size_t buffer_size,
+ int flags,
+ TraceOutputMode output_mode,
+ TraceMode trace_mode,
+ int interval_us) {
+ // We own trace_file now and are responsible for closing it. To account for error situations, use
+ // a specialized unique_ptr to ensure we close it on the way out (if it hasn't been passed to a
+ // Trace instance).
+ auto deleter = [](File* file) {
+ if (file != nullptr) {
+ file->MarkUnchecked(); // Don't deal with flushing requirements.
+ int result ATTRIBUTE_UNUSED = file->Close();
+ delete file;
+ }
+ };
+ std::unique_ptr<File, decltype(deleter)> trace_file(trace_file_in.release(), deleter);
+ if (trace_file != nullptr) {
+ trace_file->DisableAutoClose();
+ }
+
Thread* self = Thread::Current();
{
MutexLock mu(self, *Locks::trace_lock_);
@@ -338,23 +404,6 @@
return;
}
- // Open trace file if not going directly to ddms.
- std::unique_ptr<File> trace_file;
- if (output_mode != TraceOutputMode::kDDMS) {
- if (trace_fd < 0) {
- trace_file.reset(OS::CreateEmptyFileWriteOnly(trace_filename));
- } else {
- trace_file.reset(new File(trace_fd, "tracefile"));
- trace_file->DisableAutoClose();
- }
- if (trace_file.get() == nullptr) {
- PLOG(ERROR) << "Unable to open trace file '" << trace_filename << "'";
- ScopedObjectAccess soa(self);
- ThrowRuntimeException("Unable to open trace file '%s'", trace_filename);
- return;
- }
- }
-
Runtime* runtime = Runtime::Current();
// Enable count of allocs if specified in the flags.
@@ -372,8 +421,7 @@
LOG(ERROR) << "Trace already in progress, ignoring this request";
} else {
enable_stats = (flags && kTraceCountAllocs) != 0;
- the_trace_ = new Trace(trace_file.release(), trace_filename, buffer_size, flags, output_mode,
- trace_mode);
+ the_trace_ = new Trace(trace_file.release(), buffer_size, flags, output_mode, trace_mode);
if (trace_mode == TraceMode::kSampling) {
CHECK_PTHREAD_CALL(pthread_create, (&sampling_pthread_, nullptr, &RunSamplingThread,
reinterpret_cast<void*>(interval_us)),
@@ -595,8 +643,11 @@
static constexpr size_t kMinBufSize = 18U; // Trace header is up to 18B.
-Trace::Trace(File* trace_file, const char* trace_name, size_t buffer_size, int flags,
- TraceOutputMode output_mode, TraceMode trace_mode)
+Trace::Trace(File* trace_file,
+ size_t buffer_size,
+ int flags,
+ TraceOutputMode output_mode,
+ TraceMode trace_mode)
: trace_file_(trace_file),
buf_(new uint8_t[std::max(kMinBufSize, buffer_size)]()),
flags_(flags), trace_output_mode_(output_mode), trace_mode_(trace_mode),
@@ -605,6 +656,8 @@
start_time_(MicroTime()), clock_overhead_ns_(GetClockOverheadNanoSeconds()), cur_offset_(0),
overflow_(false), interval_us_(0), streaming_lock_(nullptr),
unique_methods_lock_(new Mutex("unique methods lock", kTracingUniqueMethodsLock)) {
+ CHECK(trace_file != nullptr || output_mode == TraceOutputMode::kDDMS);
+
uint16_t trace_version = GetTraceVersion(clock_source_);
if (output_mode == TraceOutputMode::kStreaming) {
trace_version |= 0xF0U;
@@ -625,7 +678,6 @@
cur_offset_.StoreRelaxed(kTraceHeaderLength);
if (output_mode == TraceOutputMode::kStreaming) {
- streaming_file_name_ = trace_name;
streaming_lock_ = new Mutex("tracing lock", LockLevel::kTracingStreamingLock);
seen_threads_.reset(new ThreadIDBitSet());
}
diff --git a/runtime/trace.h b/runtime/trace.h
index 86b8d00..7171f75 100644
--- a/runtime/trace.h
+++ b/runtime/trace.h
@@ -33,6 +33,10 @@
#include "globals.h"
#include "instrumentation.h"
+namespace unix_file {
+class FdFile;
+} // namespace unix_file
+
namespace art {
class ArtField;
@@ -115,10 +119,37 @@
static void SetDefaultClockSource(TraceClockSource clock_source);
- static void Start(const char* trace_filename, int trace_fd, size_t buffer_size, int flags,
- TraceOutputMode output_mode, TraceMode trace_mode, int interval_us)
+ static void Start(const char* trace_filename,
+ size_t buffer_size,
+ int flags,
+ TraceOutputMode output_mode,
+ TraceMode trace_mode,
+ int interval_us)
REQUIRES(!Locks::mutator_lock_, !Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_,
!Locks::trace_lock_);
+ static void Start(int trace_fd,
+ size_t buffer_size,
+ int flags,
+ TraceOutputMode output_mode,
+ TraceMode trace_mode,
+ int interval_us)
+ REQUIRES(!Locks::mutator_lock_, !Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_,
+ !Locks::trace_lock_);
+ static void Start(std::unique_ptr<unix_file::FdFile>&& file,
+ size_t buffer_size,
+ int flags,
+ TraceOutputMode output_mode,
+ TraceMode trace_mode,
+ int interval_us)
+ REQUIRES(!Locks::mutator_lock_, !Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_,
+ !Locks::trace_lock_);
+ static void StartDDMS(size_t buffer_size,
+ int flags,
+ TraceMode trace_mode,
+ int interval_us)
+ REQUIRES(!Locks::mutator_lock_, !Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_,
+ !Locks::trace_lock_);
+
static void Pause() REQUIRES(!Locks::trace_lock_, !Locks::thread_list_lock_);
static void Resume() REQUIRES(!Locks::trace_lock_);
@@ -212,8 +243,11 @@
static bool IsTracingEnabled() REQUIRES(!Locks::trace_lock_);
private:
- Trace(File* trace_file, const char* trace_name, size_t buffer_size, int flags,
- TraceOutputMode output_mode, TraceMode trace_mode);
+ Trace(File* trace_file,
+ size_t buffer_size,
+ int flags,
+ TraceOutputMode output_mode,
+ TraceMode trace_mode);
// The sampling interval in microseconds is passed as an argument.
static void* RunSamplingThread(void* arg) REQUIRES(!Locks::trace_lock_);
@@ -318,7 +352,6 @@
int interval_us_;
// Streaming mode data.
- std::string streaming_file_name_;
Mutex* streaming_lock_;
std::map<const DexFile*, DexIndexBitSet*> seen_methods_;
std::unique_ptr<ThreadIDBitSet> seen_threads_;
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index b07001e..cee7176 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -2765,47 +2765,61 @@
break;
case Instruction::IGET_BOOLEAN:
+ case Instruction::IGET_BOOLEAN_QUICK:
VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Boolean(), true, false);
break;
case Instruction::IGET_BYTE:
+ case Instruction::IGET_BYTE_QUICK:
VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Byte(), true, false);
break;
case Instruction::IGET_CHAR:
+ case Instruction::IGET_CHAR_QUICK:
VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Char(), true, false);
break;
case Instruction::IGET_SHORT:
+ case Instruction::IGET_SHORT_QUICK:
VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Short(), true, false);
break;
case Instruction::IGET:
+ case Instruction::IGET_QUICK:
VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Integer(), true, false);
break;
case Instruction::IGET_WIDE:
+ case Instruction::IGET_WIDE_QUICK:
VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.LongLo(), true, false);
break;
case Instruction::IGET_OBJECT:
+ case Instruction::IGET_OBJECT_QUICK:
VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.JavaLangObject(false), false,
false);
break;
case Instruction::IPUT_BOOLEAN:
+ case Instruction::IPUT_BOOLEAN_QUICK:
VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Boolean(), true, false);
break;
case Instruction::IPUT_BYTE:
+ case Instruction::IPUT_BYTE_QUICK:
VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Byte(), true, false);
break;
case Instruction::IPUT_CHAR:
+ case Instruction::IPUT_CHAR_QUICK:
VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Char(), true, false);
break;
case Instruction::IPUT_SHORT:
+ case Instruction::IPUT_SHORT_QUICK:
VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Short(), true, false);
break;
case Instruction::IPUT:
+ case Instruction::IPUT_QUICK:
VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Integer(), true, false);
break;
case Instruction::IPUT_WIDE:
+ case Instruction::IPUT_WIDE_QUICK:
VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.LongLo(), true, false);
break;
case Instruction::IPUT_OBJECT:
+ case Instruction::IPUT_OBJECT_QUICK:
VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.JavaLangObject(false), false,
false);
break;
@@ -2859,9 +2873,12 @@
case Instruction::INVOKE_VIRTUAL:
case Instruction::INVOKE_VIRTUAL_RANGE:
case Instruction::INVOKE_SUPER:
- case Instruction::INVOKE_SUPER_RANGE: {
+ case Instruction::INVOKE_SUPER_RANGE:
+ case Instruction::INVOKE_VIRTUAL_QUICK:
+ case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: {
bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE ||
- inst->Opcode() == Instruction::INVOKE_SUPER_RANGE);
+ inst->Opcode() == Instruction::INVOKE_SUPER_RANGE ||
+ inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
bool is_super = (inst->Opcode() == Instruction::INVOKE_SUPER ||
inst->Opcode() == Instruction::INVOKE_SUPER_RANGE);
MethodType type = is_super ? METHOD_SUPER : METHOD_VIRTUAL;
@@ -2881,7 +2898,7 @@
}
}
if (return_type == nullptr) {
- uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
+ uint32_t method_idx = GetMethodIdxOfInvoke(inst);
const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
dex::TypeIndex return_type_idx =
dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
@@ -3368,67 +3385,6 @@
}
}
break;
- // Note: the following instructions encode offsets derived from class linking.
- // As such they use Class*/Field*/Executable* as these offsets only have
- // meaning if the class linking and resolution were successful.
- case Instruction::IGET_QUICK:
- VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Integer(), true);
- break;
- case Instruction::IGET_WIDE_QUICK:
- VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.LongLo(), true);
- break;
- case Instruction::IGET_OBJECT_QUICK:
- VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.JavaLangObject(false), false);
- break;
- case Instruction::IGET_BOOLEAN_QUICK:
- VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Boolean(), true);
- break;
- case Instruction::IGET_BYTE_QUICK:
- VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Byte(), true);
- break;
- case Instruction::IGET_CHAR_QUICK:
- VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Char(), true);
- break;
- case Instruction::IGET_SHORT_QUICK:
- VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Short(), true);
- break;
- case Instruction::IPUT_QUICK:
- VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Integer(), true);
- break;
- case Instruction::IPUT_BOOLEAN_QUICK:
- VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Boolean(), true);
- break;
- case Instruction::IPUT_BYTE_QUICK:
- VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Byte(), true);
- break;
- case Instruction::IPUT_CHAR_QUICK:
- VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Char(), true);
- break;
- case Instruction::IPUT_SHORT_QUICK:
- VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Short(), true);
- break;
- case Instruction::IPUT_WIDE_QUICK:
- VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.LongLo(), true);
- break;
- case Instruction::IPUT_OBJECT_QUICK:
- VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.JavaLangObject(false), false);
- break;
- case Instruction::INVOKE_VIRTUAL_QUICK:
- case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: {
- bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
- ArtMethod* called_method = VerifyInvokeVirtualQuickArgs(inst, is_range);
- if (called_method != nullptr) {
- const char* descriptor = called_method->GetReturnTypeDescriptor();
- const RegType& return_type = reg_types_.FromDescriptor(GetClassLoader(), descriptor, false);
- if (!return_type.IsLowHalf()) {
- work_line_->SetResultRegisterType(this, return_type);
- } else {
- work_line_->SetResultRegisterTypeWide(return_type, return_type.HighHalf(®_types_));
- }
- just_set_result = true;
- }
- break;
- }
/* These should never appear during verification. */
case Instruction::UNUSED_3E ... Instruction::UNUSED_43:
@@ -3995,7 +3951,7 @@
}
} else {
// Check whether the name of the called method is "<init>"
- const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
+ const uint32_t method_idx = GetMethodIdxOfInvoke(inst);
if (strcmp(dex_file_->GetMethodName(dex_file_->GetMethodId(method_idx)), "<init>") != 0) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "'this' arg must be initialized";
return nullptr;
@@ -4017,7 +3973,7 @@
res_method_class = &FromClass(klass->GetDescriptor(&temp), klass,
klass->CannotBeAssignedFromOtherTypes());
} else {
- const uint32_t method_idx = inst->VRegB();
+ const uint32_t method_idx = GetMethodIdxOfInvoke(inst);
const dex::TypeIndex class_idx = dex_file_->GetMethodId(method_idx).class_idx_;
res_method_class = ®_types_.FromDescriptor(
GetClassLoader(),
@@ -4108,7 +4064,7 @@
// As the method may not have been resolved, make this static check against what we expect.
// The main reason for this code block is to fail hard when we find an illegal use, e.g.,
// wrong number of arguments or wrong primitive types, even if the method could not be resolved.
- const uint32_t method_idx = inst->VRegB();
+ const uint32_t method_idx = GetMethodIdxOfInvoke(inst);
DexFileParameterIterator it(*dex_file_,
dex_file_->GetProtoId(dex_file_->GetMethodId(method_idx).proto_idx_));
VerifyInvocationArgsFromIterator(&it, inst, method_type, is_range, nullptr);
@@ -4181,7 +4137,7 @@
const Instruction* inst, MethodType method_type, bool is_range) {
// Resolve the method. This could be an abstract or concrete method depending on what sort of call
// we're making.
- const uint32_t method_idx = inst->VRegB();
+ const uint32_t method_idx = GetMethodIdxOfInvoke(inst);
ArtMethod* res_method = ResolveMethodAndCheckAccess(method_idx, method_type);
if (res_method == nullptr) { // error or class is unresolved
// Check what we can statically.
@@ -4334,122 +4290,34 @@
return true;
}
-ArtMethod* MethodVerifier::GetQuickInvokedMethod(const Instruction* inst, bool is_range) {
- if (is_range) {
- DCHECK_EQ(inst->Opcode(), Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
- } else {
- DCHECK_EQ(inst->Opcode(), Instruction::INVOKE_VIRTUAL_QUICK);
+uint16_t MethodVerifier::GetMethodIdxOfInvoke(const Instruction* inst) {
+ switch (inst->Opcode()) {
+ case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
+ case Instruction::INVOKE_VIRTUAL_QUICK: {
+ DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_)
+ << dex_file_->PrettyMethod(dex_method_idx_, true) << "@" << work_insn_idx_;
+ DCHECK(method_being_verified_ != nullptr);
+ uint16_t method_idx = method_being_verified_->GetIndexFromQuickening(work_insn_idx_);
+ CHECK_NE(method_idx, DexFile::kDexNoIndex16);
+ return method_idx;
+ }
+ default: {
+ return inst->VRegB();
+ }
}
-
- DCHECK(method_being_verified_ != nullptr);
- uint16_t method_idx = method_being_verified_->GetIndexFromQuickening(work_insn_idx_);
- CHECK_NE(method_idx, DexFile::kDexNoIndex16);
- return ResolveMethodAndCheckAccess(method_idx, METHOD_VIRTUAL);
}
-ArtMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instruction* inst, bool is_range) {
- DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_)
- << dex_file_->PrettyMethod(dex_method_idx_, true) << "@" << work_insn_idx_;
-
- ArtMethod* res_method = GetQuickInvokedMethod(inst, is_range);
- if (res_method == nullptr) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer method from " << inst->Name();
- return nullptr;
- }
- if (FailOrAbort(!res_method->IsDirect(),
- "Quick-invoked method is direct at ",
- work_insn_idx_)) {
- return nullptr;
- }
- if (FailOrAbort(!res_method->IsStatic(),
- "Quick-invoked method is static at ",
- work_insn_idx_)) {
- return nullptr;
- }
-
- // We use vAA as our expected arg count, rather than res_method->insSize, because we need to
- // match the call to the signature. Also, we might be calling through an abstract method
- // definition (which doesn't have register count values).
- const RegType& actual_arg_type = work_line_->GetInvocationThis(this, inst);
- if (actual_arg_type.IsConflict()) { // GetInvocationThis failed.
- return nullptr;
- }
- const size_t expected_args = (is_range) ? inst->VRegA_3rc() : inst->VRegA_35c();
- /* caught by static verifier */
- DCHECK(is_range || expected_args <= 5);
- if (expected_args > code_item_accessor_.OutsSize()) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid argument count (" << expected_args
- << ") exceeds outsSize (" << code_item_accessor_.OutsSize() << ")";
- return nullptr;
- }
-
- /*
- * Check the "this" argument, which must be an instance of the class that declared the method.
- * For an interface class, we don't do the full interface merge (see JoinClass), so we can't do a
- * rigorous check here (which is okay since we have to do it at runtime).
- */
- // Note: given an uninitialized type, this should always fail. Constructors aren't virtual.
- if (actual_arg_type.IsUninitializedTypes() && !res_method->IsConstructor()) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "'this' arg must be initialized";
- return nullptr;
- }
- if (!actual_arg_type.IsZeroOrNull()) {
- mirror::Class* klass = res_method->GetDeclaringClass();
- std::string temp;
- const RegType& res_method_class =
- FromClass(klass->GetDescriptor(&temp), klass, klass->CannotBeAssignedFromOtherTypes());
- if (!res_method_class.IsAssignableFrom(actual_arg_type, this)) {
- Fail(actual_arg_type.IsUninitializedTypes() // Just overcautious - should have never
- ? VERIFY_ERROR_BAD_CLASS_HARD // quickened this.
- : actual_arg_type.IsUnresolvedTypes()
- ? VERIFY_ERROR_NO_CLASS
- : VERIFY_ERROR_BAD_CLASS_SOFT) << "'this' argument '" << actual_arg_type
- << "' not instance of '" << res_method_class << "'";
- return nullptr;
- }
- }
- /*
- * Process the target method's signature. This signature may or may not
- * have been verified, so we can't assume it's properly formed.
- */
- const DexFile::TypeList* params = res_method->GetParameterTypeList();
- size_t params_size = params == nullptr ? 0 : params->Size();
- uint32_t arg[5];
- if (!is_range) {
- inst->GetVarArgs(arg);
- }
- size_t actual_args = 1;
- for (size_t param_index = 0; param_index < params_size; param_index++) {
- if (actual_args >= expected_args) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invalid call to '"
- << res_method->PrettyMethod()
- << "'. Expected " << expected_args
- << " arguments, processing argument " << actual_args
- << " (where longs/doubles count twice).";
- return nullptr;
- }
- const char* descriptor =
- res_method->GetTypeDescriptorFromTypeIdx(params->GetTypeItem(param_index).type_idx_);
- if (descriptor == nullptr) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invocation of "
- << res_method->PrettyMethod()
- << " missing signature component";
- return nullptr;
- }
- const RegType& reg_type = reg_types_.FromDescriptor(GetClassLoader(), descriptor, false);
- uint32_t get_reg = is_range ? inst->VRegC_3rc() + actual_args : arg[actual_args];
- if (!work_line_->VerifyRegisterType(this, get_reg, reg_type)) {
- return res_method;
- }
- actual_args = reg_type.IsLongOrDoubleTypes() ? actual_args + 2 : actual_args + 1;
- }
- if (actual_args != expected_args) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invocation of "
- << res_method->PrettyMethod() << " expected "
- << expected_args << " arguments, found " << actual_args;
- return nullptr;
+uint16_t MethodVerifier::GetFieldIdxOfFieldAccess(const Instruction* inst, bool is_static) {
+ if (is_static) {
+ return inst->VRegB_21c();
+ } else if (inst->IsQuickened()) {
+ DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_);
+ DCHECK(method_being_verified_ != nullptr);
+ uint16_t field_idx = method_being_verified_->GetIndexFromQuickening(work_insn_idx_);
+ CHECK_NE(field_idx, DexFile::kDexNoIndex16);
+ return field_idx;
} else {
- return res_method;
+ return inst->VRegC_22c();
}
}
@@ -4819,7 +4687,7 @@
template <MethodVerifier::FieldAccessType kAccType>
void MethodVerifier::VerifyISFieldAccess(const Instruction* inst, const RegType& insn_type,
bool is_primitive, bool is_static) {
- uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
+ uint32_t field_idx = GetFieldIdxOfFieldAccess(inst, is_static);
ArtField* field;
if (is_static) {
field = GetStaticField(field_idx);
@@ -4972,151 +4840,6 @@
}
}
-ArtField* MethodVerifier::GetQuickAccessedField() {
- DCHECK(method_being_verified_ != nullptr);
- uint16_t field_idx = method_being_verified_->GetIndexFromQuickening(work_insn_idx_);
- CHECK_NE(field_idx, DexFile::kDexNoIndex16);
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- ArtField* field = class_linker->ResolveFieldJLS(field_idx, dex_cache_, class_loader_);
- if (field == nullptr) {
- DCHECK(self_->IsExceptionPending());
- self_->ClearException();
- }
- return field;
-}
-
-template <MethodVerifier::FieldAccessType kAccType>
-void MethodVerifier::VerifyQuickFieldAccess(const Instruction* inst, const RegType& insn_type,
- bool is_primitive) {
- DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_);
-
- ArtField* field = GetQuickAccessedField();
- if (field == nullptr) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field from " << inst->Name();
- return;
- }
-
- // For an IPUT_QUICK, we now test for final flag of the field.
- if (kAccType == FieldAccessType::kAccPut) {
- if (field->IsFinal() && field->GetDeclaringClass() != GetDeclaringClass().GetClass()) {
- Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot modify final field " << field->PrettyField()
- << " from other class " << GetDeclaringClass();
- return;
- }
- }
-
- // Get the field type.
- const RegType* field_type;
- {
- ObjPtr<mirror::Class> field_type_class =
- can_load_classes_ ? field->ResolveType() : field->LookupResolvedType();
-
- if (field_type_class != nullptr) {
- field_type = &FromClass(field->GetTypeDescriptor(),
- field_type_class.Ptr(),
- field_type_class->CannotBeAssignedFromOtherTypes());
- } else {
- Thread* self = Thread::Current();
- DCHECK(!can_load_classes_ || self->IsExceptionPending());
- self->ClearException();
- field_type = ®_types_.FromDescriptor(field->GetDeclaringClass()->GetClassLoader(),
- field->GetTypeDescriptor(),
- false);
- }
- if (field_type == nullptr) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field type from " << inst->Name();
- return;
- }
- }
-
- const uint32_t vregA = inst->VRegA_22c();
- static_assert(kAccType == FieldAccessType::kAccPut || kAccType == FieldAccessType::kAccGet,
- "Unexpected third access type");
- if (kAccType == FieldAccessType::kAccPut) {
- if (is_primitive) {
- // Primitive field assignability rules are weaker than regular assignability rules
- bool instruction_compatible;
- bool value_compatible;
- const RegType& value_type = work_line_->GetRegisterType(this, vregA);
- if (field_type->IsIntegralTypes()) {
- instruction_compatible = insn_type.IsIntegralTypes();
- value_compatible = value_type.IsIntegralTypes();
- } else if (field_type->IsFloat()) {
- instruction_compatible = insn_type.IsInteger(); // no [is]put-float, so expect [is]put-int
- value_compatible = value_type.IsFloatTypes();
- } else if (field_type->IsLong()) {
- instruction_compatible = insn_type.IsLong();
- value_compatible = value_type.IsLongTypes();
- } else if (field_type->IsDouble()) {
- instruction_compatible = insn_type.IsLong(); // no [is]put-double, so expect [is]put-long
- value_compatible = value_type.IsDoubleTypes();
- } else {
- instruction_compatible = false; // reference field with primitive store
- value_compatible = false; // unused
- }
- if (!instruction_compatible) {
- // This is a global failure rather than a class change failure as the instructions and
- // the descriptors for the type should have been consistent within the same file at
- // compile time
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << ArtField::PrettyField(field)
- << " to be of type '" << insn_type
- << "' but found type '" << *field_type
- << "' in put";
- return;
- }
- if (!value_compatible) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected value in v" << vregA
- << " of type " << value_type
- << " but expected " << *field_type
- << " for store to " << ArtField::PrettyField(field) << " in put";
- return;
- }
- } else {
- if (!insn_type.IsAssignableFrom(*field_type, this)) {
- Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << ArtField::PrettyField(field)
- << " to be compatible with type '" << insn_type
- << "' but found type '" << *field_type
- << "' in put-object";
- return;
- }
- work_line_->VerifyRegisterType(this, vregA, *field_type);
- }
- } else if (kAccType == FieldAccessType::kAccGet) {
- if (is_primitive) {
- if (field_type->Equals(insn_type) ||
- (field_type->IsFloat() && insn_type.IsIntegralTypes()) ||
- (field_type->IsDouble() && insn_type.IsLongTypes())) {
- // expected that read is of the correct primitive type or that int reads are reading
- // floats or long reads are reading doubles
- } else {
- // This is a global failure rather than a class change failure as the instructions and
- // the descriptors for the type should have been consistent within the same file at
- // compile time
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << ArtField::PrettyField(field)
- << " to be of type '" << insn_type
- << "' but found type '" << *field_type << "' in Get";
- return;
- }
- } else {
- if (!insn_type.IsAssignableFrom(*field_type, this)) {
- Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << ArtField::PrettyField(field)
- << " to be compatible with type '" << insn_type
- << "' but found type '" << *field_type
- << "' in get-object";
- work_line_->SetRegisterType<LockOp::kClear>(this, vregA, reg_types_.Conflict());
- return;
- }
- }
- if (!field_type->IsLowHalf()) {
- work_line_->SetRegisterType<LockOp::kClear>(this, vregA, *field_type);
- } else {
- work_line_->SetRegisterTypeWide(this, vregA, *field_type, field_type->HighHalf(®_types_));
- }
- } else {
- LOG(FATAL) << "Unexpected case.";
- }
-}
-
bool MethodVerifier::CheckNotMoveException(const uint16_t* insns, int insn_idx) {
if ((insns[insn_idx] & 0xff) == Instruction::MOVE_EXCEPTION) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid use of move-exception";
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 9237a8b..531d3da 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -209,12 +209,12 @@
const RegType& ResolveCheckedClass(dex::TypeIndex class_idx)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Returns the method of a quick invoke or null if it cannot be found.
- ArtMethod* GetQuickInvokedMethod(const Instruction* inst, bool is_range)
+ // Returns the method index of an invoke instruction.
+ uint16_t GetMethodIdxOfInvoke(const Instruction* inst)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Returns the access field of a quick field access (iget/iput-quick) or null
- // if it cannot be found.
- ArtField* GetQuickAccessedField() REQUIRES_SHARED(Locks::mutator_lock_);
+ // Returns the field index of a field access instruction.
+ uint16_t GetFieldIdxOfFieldAccess(const Instruction* inst, bool is_static)
+ REQUIRES_SHARED(Locks::mutator_lock_);
uint32_t GetEncounteredFailureTypes() {
return encountered_failure_types_;
@@ -575,10 +575,6 @@
bool is_primitive, bool is_static)
REQUIRES_SHARED(Locks::mutator_lock_);
- template <FieldAccessType kAccType>
- void VerifyQuickFieldAccess(const Instruction* inst, const RegType& insn_type, bool is_primitive)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
enum class CheckAccess { // private.
kYes,
kNo,
@@ -642,9 +638,6 @@
ArtMethod* res_method)
REQUIRES_SHARED(Locks::mutator_lock_);
- ArtMethod* VerifyInvokeVirtualQuickArgs(const Instruction* inst, bool is_range)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
/*
* Verify the arguments present for a call site. Returns "true" if all is well, "false" otherwise.
*/
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 67ea64b..bf36ccf 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -24,6 +24,7 @@
#include <android-base/stringprintf.h>
#include "entrypoints/quick/quick_entrypoints_enum.h"
+#include "hidden_api.h"
#include "jni_internal.h"
#include "mirror/class.h"
#include "mirror/throwable.h"
@@ -287,17 +288,17 @@
public:
explicit ScopedHiddenApiExemption(Runtime* runtime)
: runtime_(runtime),
- initially_enabled_(runtime_->AreHiddenApiChecksEnabled()) {
- runtime_->SetHiddenApiChecksEnabled(false);
+ initial_policy_(runtime_->GetHiddenApiEnforcementPolicy()) {
+ runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kNoChecks);
}
~ScopedHiddenApiExemption() {
- runtime_->SetHiddenApiChecksEnabled(initially_enabled_);
+ runtime_->SetHiddenApiEnforcementPolicy(initial_policy_);
}
private:
Runtime* runtime_;
- const bool initially_enabled_;
+ const hiddenapi::EnforcementPolicy initial_policy_;
DISALLOW_COPY_AND_ASSIGN(ScopedHiddenApiExemption);
};
diff --git a/test/121-modifiers/classes/A$B.class b/test/121-modifiers/classes/A$B.class
deleted file mode 100644
index bd7ebfe..0000000
--- a/test/121-modifiers/classes/A$B.class
+++ /dev/null
Binary files differ
diff --git a/test/121-modifiers/classes/A$C.class b/test/121-modifiers/classes/A$C.class
deleted file mode 100644
index 3ae872e..0000000
--- a/test/121-modifiers/classes/A$C.class
+++ /dev/null
Binary files differ
diff --git a/test/121-modifiers/classes/A.class b/test/121-modifiers/classes/A.class
deleted file mode 100644
index d89d029..0000000
--- a/test/121-modifiers/classes/A.class
+++ /dev/null
Binary files differ
diff --git a/test/121-modifiers/classes/Inf.class b/test/121-modifiers/classes/Inf.class
deleted file mode 100644
index e8dd680..0000000
--- a/test/121-modifiers/classes/Inf.class
+++ /dev/null
Binary files differ
diff --git a/test/121-modifiers/classes/Main.class b/test/121-modifiers/classes/Main.class
deleted file mode 100644
index e044074..0000000
--- a/test/121-modifiers/classes/Main.class
+++ /dev/null
Binary files differ
diff --git a/test/121-modifiers/classes/NonInf.class b/test/121-modifiers/classes/NonInf.class
deleted file mode 100644
index 0f1e826..0000000
--- a/test/121-modifiers/classes/NonInf.class
+++ /dev/null
Binary files differ
diff --git a/test/121-modifiers/info.txt b/test/121-modifiers/info.txt
index 335df53..7dba113 100644
--- a/test/121-modifiers/info.txt
+++ b/test/121-modifiers/info.txt
@@ -10,9 +10,9 @@
javac Inf.java NonInf.java Main.java
javac -cp asm.jar:asm-tree.jar:. Asm.java
java -cp asm.jar:asm-tree.jar:. Asm
-mv Inf.out classes/Inf.class
-mv NonInf.out classes/NonInf.class
-mv Main.class A.class A\$B.class A\$C.class classes/
+mv Inf.out classes_tmp/Inf.class
+mv NonInf.out classes_tmp/NonInf.class
+mv Main.class A.class A\$B.class A\$C.class classes_tmp/
dx --debug --dex --output=classes.dex classes
baksmali disassemble classes.dex
mv out/*.smali smali/
diff --git a/test/161-final-abstract-class/smali/Main.smali b/test/161-final-abstract-class/smali/Main.smali
new file mode 100644
index 0000000..588854c
--- /dev/null
+++ b/test/161-final-abstract-class/smali/Main.smali
@@ -0,0 +1,214 @@
+# Created with baksmali.
+
+# Java file for reference.
+
+# import java.lang.reflect.InvocationTargetException;
+# import java.lang.reflect.Method;
+#
+# public class Main {
+# public static void main(String[] args) {
+# try {
+# // Make sure that the abstract final class is marked as erroneous.
+# Class.forName("AbstractFinal");
+# System.out.println("UNREACHABLE!");
+# } catch (VerifyError expected) {
+# } catch (Throwable t) {
+# t.printStackTrace(System.out);
+# }
+# try {
+# // Verification of TestClass.test() used to crash when processing
+# // the final abstract (erroneous) class.
+# Class<?> tc = Class.forName("TestClass");
+# Method test = tc.getDeclaredMethod("test");
+# test.invoke(null);
+# System.out.println("UNREACHABLE!");
+# } catch (InvocationTargetException ite) {
+# if (ite.getCause() instanceof InstantiationError) {
+# System.out.println(
+# ite.getCause().getClass().getName() + ": " + ite.getCause().getMessage());
+# } else {
+# ite.printStackTrace(System.out);
+# }
+# } catch (Throwable t) {
+# t.printStackTrace(System.out);
+# }
+# }
+# }
+
+.class public LMain;
+.super Ljava/lang/Object;
+.source "Main.java"
+
+
+# direct methods
+.method public constructor <init>()V
+ .registers 1
+
+ .line 20
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+
+ return-void
+.end method
+
+.method public static main([Ljava/lang/String;)V
+ .registers 4
+
+ .line 24
+ :try_start_0
+ const-string p0, "AbstractFinal"
+
+ invoke-static {p0}, Ljava/lang/Class;->forName(Ljava/lang/String;)Ljava/lang/Class;
+
+ .line 25
+ sget-object p0, Ljava/lang/System;->out:Ljava/io/PrintStream;
+
+ const-string v0, "UNREACHABLE!"
+
+ invoke-virtual {p0, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+ :try_end_c
+ .catch Ljava/lang/VerifyError; {:try_start_0 .. :try_end_c} :catch_14
+ .catch Ljava/lang/Throwable; {:try_start_0 .. :try_end_c} :catch_d
+
+ goto :goto_15
+
+ .line 27
+ :catch_d
+ move-exception p0
+
+ .line 28
+ sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
+
+ invoke-virtual {p0, v0}, Ljava/lang/Throwable;->printStackTrace(Ljava/io/PrintStream;)V
+
+ goto :goto_16
+
+ .line 26
+ :catch_14
+ move-exception p0
+
+ .line 29
+ :goto_15
+ nop
+
+ .line 33
+ :goto_16
+ :try_start_16
+ const-string p0, "TestClass"
+
+ invoke-static {p0}, Ljava/lang/Class;->forName(Ljava/lang/String;)Ljava/lang/Class;
+
+ move-result-object p0
+
+ .line 34
+ const-string v0, "test"
+
+ const/4 v1, 0x0
+
+ new-array v2, v1, [Ljava/lang/Class;
+
+ invoke-virtual {p0, v0, v2}, Ljava/lang/Class;->getDeclaredMethod(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
+
+ move-result-object p0
+
+ .line 35
+ const/4 v0, 0x0
+
+ new-array v1, v1, [Ljava/lang/Object;
+
+ invoke-virtual {p0, v0, v1}, Ljava/lang/reflect/Method;->invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;
+
+ .line 36
+ sget-object p0, Ljava/lang/System;->out:Ljava/io/PrintStream;
+
+ const-string v0, "UNREACHABLE!"
+
+ invoke-virtual {p0, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+ :try_end_32
+ .catch Ljava/lang/reflect/InvocationTargetException; {:try_start_16 .. :try_end_32} :catch_3a
+ .catch Ljava/lang/Throwable; {:try_start_16 .. :try_end_32} :catch_33
+
+ goto :goto_76
+
+ .line 44
+ :catch_33
+ move-exception p0
+
+ .line 45
+ sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
+
+ invoke-virtual {p0, v0}, Ljava/lang/Throwable;->printStackTrace(Ljava/io/PrintStream;)V
+
+ goto :goto_77
+
+ .line 37
+ :catch_3a
+ move-exception p0
+
+ .line 38
+ invoke-virtual {p0}, Ljava/lang/reflect/InvocationTargetException;->getCause()Ljava/lang/Throwable;
+
+ move-result-object v0
+
+ instance-of v0, v0, Ljava/lang/InstantiationError;
+
+ if-eqz v0, :cond_71
+
+ .line 39
+ sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
+
+ new-instance v1, Ljava/lang/StringBuilder;
+
+ invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V
+
+ .line 40
+ invoke-virtual {p0}, Ljava/lang/reflect/InvocationTargetException;->getCause()Ljava/lang/Throwable;
+
+ move-result-object v2
+
+ invoke-virtual {v2}, Ljava/lang/Object;->getClass()Ljava/lang/Class;
+
+ move-result-object v2
+
+ invoke-virtual {v2}, Ljava/lang/Class;->getName()Ljava/lang/String;
+
+ move-result-object v2
+
+ invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+
+ const-string v2, ": "
+
+ invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+
+ invoke-virtual {p0}, Ljava/lang/reflect/InvocationTargetException;->getCause()Ljava/lang/Throwable;
+
+ move-result-object p0
+
+ invoke-virtual {p0}, Ljava/lang/Throwable;->getMessage()Ljava/lang/String;
+
+ move-result-object p0
+
+ invoke-virtual {v1, p0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+
+ invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
+
+ move-result-object p0
+
+ .line 39
+ invoke-virtual {v0, p0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+
+ goto :goto_76
+
+ .line 42
+ :cond_71
+ sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
+
+ invoke-virtual {p0, v0}, Ljava/lang/reflect/InvocationTargetException;->printStackTrace(Ljava/io/PrintStream;)V
+
+ .line 46
+ :goto_76
+ nop
+
+ .line 47
+ :goto_77
+ return-void
+.end method
diff --git a/test/161-final-abstract-class/src/Main.java b/test/161-final-abstract-class/src/Main.java
deleted file mode 100644
index 2452490..0000000
--- a/test/161-final-abstract-class/src/Main.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-public class Main {
- public static void main(String[] args) {
- try {
- // Make sure that the abstract final class is marked as erroneous.
- Class.forName("AbstractFinal");
- System.out.println("UNREACHABLE!");
- } catch (VerifyError expected) {
- } catch (Throwable t) {
- t.printStackTrace(System.out);
- }
- try {
- // Verification of TestClass.test() used to crash when processing
- // the final abstract (erroneous) class.
- Class<?> tc = Class.forName("TestClass");
- Method test = tc.getDeclaredMethod("test");
- test.invoke(null);
- System.out.println("UNREACHABLE!");
- } catch (InvocationTargetException ite) {
- if (ite.getCause() instanceof InstantiationError) {
- System.out.println(
- ite.getCause().getClass().getName() + ": " + ite.getCause().getMessage());
- } else {
- ite.printStackTrace(System.out);
- }
- } catch (Throwable t) {
- t.printStackTrace(System.out);
- }
- }
-}
diff --git a/test/1929-exception-catch-exception/expected.txt b/test/1929-exception-catch-exception/expected.txt
index bc5608a..a82b732 100644
--- a/test/1929-exception-catch-exception/expected.txt
+++ b/test/1929-exception-catch-exception/expected.txt
@@ -1,11 +1,11 @@
Test "art.Test1929$DoThrowClass": Running breakpoint with handler "art.Test1929$DoNothingHandler"
-main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: doThrow
+main: public static void art.Test1929.run() throws java.lang.Exception @ line = 298 caught class art.Test1929$TestException: doThrow
Current Stack:
private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
private static void art.Test1929.PrintStack() @ line = 52
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
- public static void art.Test1929.run() throws java.lang.Exception @ line = 283
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 298
Test "art.Test1929$DoThrowClass": Caught error art.Test1929$TestException:"doThrow" with handler "art.Test1929$DoNothingHandler"
Test "art.Test1929$DoThrowClass": Finished running with handler "art.Test1929$DoNothingHandler"
Test "art.Test1929$DoThrowCatchBaseTestException": Running breakpoint with handler "art.Test1929$DoNothingHandler"
@@ -17,71 +17,71 @@
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
public static void art.Test1929.throwCatchBaseTestException() @ line = 140
public void art.Test1929$DoThrowCatchBaseTestException.run() @ line = 149
- public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 295
Doing nothing!
Caught art.Test1929$TestException: "throwCatchBaseTestException"
Test "art.Test1929$DoThrowCatchBaseTestException": No error caught with handler "art.Test1929$DoNothingHandler"
Test "art.Test1929$DoThrowCatchBaseTestException": Finished running with handler "art.Test1929$DoNothingHandler"
Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Running breakpoint with handler "art.Test1929$DoNothingHandler"
-main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice
+main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 157 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice
Current Stack:
private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
private static void art.Test1929.PrintStack() @ line = 52
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
- public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161
- public static void art.Test1929.throwCatchBaseTestExceptionTwice() @ line = 197
- public void art.Test1929$DoThrowCatchBaseTestExceptionTwice.run() @ line = 201
- public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+ public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 157
+ public static void art.Test1929.throwCatchBaseTestExceptionTwice() @ line = 203
+ public void art.Test1929$DoThrowCatchBaseTestExceptionTwice.run() @ line = 210
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 295
Caught art.Test1929$TestException: "throwCatchBaseTestExceptionTwice"
Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": No error caught with handler "art.Test1929$DoNothingHandler"
Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Finished running with handler "art.Test1929$DoNothingHandler"
Test "art.Test1929$DoThrowCatchTestException": Running breakpoint with handler "art.Test1929$DoNothingHandler"
-main: public static void art.Test1929.throwCatchTestException() @ line = 207 caught class art.Test1929$TestException: throwCatchTestException
+main: public static void art.Test1929.throwCatchTestException() @ line = 216 caught class art.Test1929$TestException: throwCatchTestException
Current Stack:
private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
private static void art.Test1929.PrintStack() @ line = 52
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
- public static void art.Test1929.throwCatchTestException() @ line = 207
- public void art.Test1929$DoThrowCatchTestException.run() @ line = 216
- public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+ public static void art.Test1929.throwCatchTestException() @ line = 216
+ public void art.Test1929$DoThrowCatchTestException.run() @ line = 225
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 295
Doing nothing!
Caught art.Test1929$TestException: "throwCatchTestException"
Test "art.Test1929$DoThrowCatchTestException": No error caught with handler "art.Test1929$DoNothingHandler"
Test "art.Test1929$DoThrowCatchTestException": Finished running with handler "art.Test1929$DoNothingHandler"
Test "art.Test1929$DoThrowCatchTestExceptionTwice": Running breakpoint with handler "art.Test1929$DoNothingHandler"
-main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 caught class art.Test1929$TestException: throwCatchTestExceptionTwice
+main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 175 caught class art.Test1929$TestException: throwCatchTestExceptionTwice
Current Stack:
private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
private static void art.Test1929.PrintStack() @ line = 52
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
- public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179
- public static void art.Test1929.throwCatchTestExceptionTwice() @ line = 222
- public void art.Test1929$DoThrowCatchTestExceptionTwice.run() @ line = 226
- public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+ public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 175
+ public static void art.Test1929.throwCatchTestExceptionTwice() @ line = 234
+ public void art.Test1929$DoThrowCatchTestExceptionTwice.run() @ line = 241
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 295
Caught art.Test1929$TestException: "throwCatchTestExceptionTwice"
Test "art.Test1929$DoThrowCatchTestExceptionTwice": No error caught with handler "art.Test1929$DoNothingHandler"
Test "art.Test1929$DoThrowCatchTestExceptionTwice": Finished running with handler "art.Test1929$DoNothingHandler"
Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Running breakpoint with handler "art.Test1929$DoNothingHandler"
-main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow
+main: public static void art.Test1929.run() throws java.lang.Exception @ line = 298 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow
Current Stack:
private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
private static void art.Test1929.PrintStack() @ line = 52
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
- public static void art.Test1929.run() throws java.lang.Exception @ line = 283
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 298
Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Caught error art.Test1929$TestException:"throwCatchTestExceptionNoRethrow" with handler "art.Test1929$DoNothingHandler"
Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Finished running with handler "art.Test1929$DoNothingHandler"
Test "art.Test1929$DoThrowClass": Running breakpoint with handler "art.Test1929$ThrowCatchBase"
-main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: doThrow
+main: public static void art.Test1929.run() throws java.lang.Exception @ line = 298 caught class art.Test1929$TestException: doThrow
Current Stack:
private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
private static void art.Test1929.PrintStack() @ line = 52
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
- public static void art.Test1929.run() throws java.lang.Exception @ line = 283
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 298
Test "art.Test1929$DoThrowClass": Caught error art.Test1929$TestException:"doThrow" with handler "art.Test1929$ThrowCatchBase"
Test "art.Test1929$DoThrowClass": Finished running with handler "art.Test1929$ThrowCatchBase"
Test "art.Test1929$DoThrowCatchBaseTestException": Running breakpoint with handler "art.Test1929$ThrowCatchBase"
@@ -93,73 +93,73 @@
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
public static void art.Test1929.throwCatchBaseTestException() @ line = 140
public void art.Test1929$DoThrowCatchBaseTestException.run() @ line = 149
- public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 295
Throwing BaseTestException and catching it!
Caught art.Test1929$BaseTestException: "ThrowBaseHandler during throw from public static void art.Test1929.throwCatchBaseTestException() @ line = 140"
Caught art.Test1929$TestException: "throwCatchBaseTestException"
Test "art.Test1929$DoThrowCatchBaseTestException": No error caught with handler "art.Test1929$ThrowCatchBase"
Test "art.Test1929$DoThrowCatchBaseTestException": Finished running with handler "art.Test1929$ThrowCatchBase"
Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Running breakpoint with handler "art.Test1929$ThrowCatchBase"
-main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice
+main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 157 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice
Current Stack:
private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
private static void art.Test1929.PrintStack() @ line = 52
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
- public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161
- public static void art.Test1929.throwCatchBaseTestExceptionTwice() @ line = 197
- public void art.Test1929$DoThrowCatchBaseTestExceptionTwice.run() @ line = 201
- public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+ public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 157
+ public static void art.Test1929.throwCatchBaseTestExceptionTwice() @ line = 203
+ public void art.Test1929$DoThrowCatchBaseTestExceptionTwice.run() @ line = 210
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 295
Caught art.Test1929$TestException: "throwCatchBaseTestExceptionTwice"
Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": No error caught with handler "art.Test1929$ThrowCatchBase"
Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Finished running with handler "art.Test1929$ThrowCatchBase"
Test "art.Test1929$DoThrowCatchTestException": Running breakpoint with handler "art.Test1929$ThrowCatchBase"
-main: public static void art.Test1929.throwCatchTestException() @ line = 207 caught class art.Test1929$TestException: throwCatchTestException
+main: public static void art.Test1929.throwCatchTestException() @ line = 216 caught class art.Test1929$TestException: throwCatchTestException
Current Stack:
private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
private static void art.Test1929.PrintStack() @ line = 52
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
- public static void art.Test1929.throwCatchTestException() @ line = 207
- public void art.Test1929$DoThrowCatchTestException.run() @ line = 216
- public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+ public static void art.Test1929.throwCatchTestException() @ line = 216
+ public void art.Test1929$DoThrowCatchTestException.run() @ line = 225
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 295
Throwing BaseTestException and catching it!
-Caught art.Test1929$BaseTestException: "ThrowBaseHandler during throw from public static void art.Test1929.throwCatchTestException() @ line = 207"
+Caught art.Test1929$BaseTestException: "ThrowBaseHandler during throw from public static void art.Test1929.throwCatchTestException() @ line = 216"
Caught art.Test1929$TestException: "throwCatchTestException"
Test "art.Test1929$DoThrowCatchTestException": No error caught with handler "art.Test1929$ThrowCatchBase"
Test "art.Test1929$DoThrowCatchTestException": Finished running with handler "art.Test1929$ThrowCatchBase"
Test "art.Test1929$DoThrowCatchTestExceptionTwice": Running breakpoint with handler "art.Test1929$ThrowCatchBase"
-main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 caught class art.Test1929$TestException: throwCatchTestExceptionTwice
+main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 175 caught class art.Test1929$TestException: throwCatchTestExceptionTwice
Current Stack:
private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
private static void art.Test1929.PrintStack() @ line = 52
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
- public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179
- public static void art.Test1929.throwCatchTestExceptionTwice() @ line = 222
- public void art.Test1929$DoThrowCatchTestExceptionTwice.run() @ line = 226
- public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+ public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 175
+ public static void art.Test1929.throwCatchTestExceptionTwice() @ line = 234
+ public void art.Test1929$DoThrowCatchTestExceptionTwice.run() @ line = 241
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 295
Caught art.Test1929$TestException: "throwCatchTestExceptionTwice"
Test "art.Test1929$DoThrowCatchTestExceptionTwice": No error caught with handler "art.Test1929$ThrowCatchBase"
Test "art.Test1929$DoThrowCatchTestExceptionTwice": Finished running with handler "art.Test1929$ThrowCatchBase"
Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Running breakpoint with handler "art.Test1929$ThrowCatchBase"
-main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow
+main: public static void art.Test1929.run() throws java.lang.Exception @ line = 298 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow
Current Stack:
private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
private static void art.Test1929.PrintStack() @ line = 52
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
- public static void art.Test1929.run() throws java.lang.Exception @ line = 283
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 298
Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Caught error art.Test1929$TestException:"throwCatchTestExceptionNoRethrow" with handler "art.Test1929$ThrowCatchBase"
Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Finished running with handler "art.Test1929$ThrowCatchBase"
Test "art.Test1929$DoThrowClass": Running breakpoint with handler "art.Test1929$ThrowBaseTestExceptionHandler"
-main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: doThrow
+main: public static void art.Test1929.run() throws java.lang.Exception @ line = 298 caught class art.Test1929$TestException: doThrow
Current Stack:
private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
private static void art.Test1929.PrintStack() @ line = 52
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
- public static void art.Test1929.run() throws java.lang.Exception @ line = 283
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 298
Test "art.Test1929$DoThrowClass": Caught error art.Test1929$TestException:"doThrow" with handler "art.Test1929$ThrowBaseTestExceptionHandler"
Test "art.Test1929$DoThrowClass": Finished running with handler "art.Test1929$ThrowBaseTestExceptionHandler"
Test "art.Test1929$DoThrowCatchBaseTestException": Running breakpoint with handler "art.Test1929$ThrowBaseTestExceptionHandler"
@@ -171,69 +171,69 @@
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
public static void art.Test1929.throwCatchBaseTestException() @ line = 140
public void art.Test1929$DoThrowCatchBaseTestException.run() @ line = 149
- public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 295
Throwing BaseTestException!
Test "art.Test1929$DoThrowCatchBaseTestException": Caught error art.Test1929$BaseTestException:"ThrowBaseHandler during throw from public static void art.Test1929.throwCatchBaseTestException() @ line = 140" with handler "art.Test1929$ThrowBaseTestExceptionHandler"
Test "art.Test1929$DoThrowCatchBaseTestException": Finished running with handler "art.Test1929$ThrowBaseTestExceptionHandler"
Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Running breakpoint with handler "art.Test1929$ThrowBaseTestExceptionHandler"
-main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice
+main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 157 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice
Current Stack:
private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
private static void art.Test1929.PrintStack() @ line = 52
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
- public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161
- public static void art.Test1929.throwCatchBaseTestExceptionTwice() @ line = 197
- public void art.Test1929$DoThrowCatchBaseTestExceptionTwice.run() @ line = 201
- public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+ public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 157
+ public static void art.Test1929.throwCatchBaseTestExceptionTwice() @ line = 203
+ public void art.Test1929$DoThrowCatchBaseTestExceptionTwice.run() @ line = 210
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 295
Caught art.Test1929$TestException: "throwCatchBaseTestExceptionTwice"
Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": No error caught with handler "art.Test1929$ThrowBaseTestExceptionHandler"
Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Finished running with handler "art.Test1929$ThrowBaseTestExceptionHandler"
Test "art.Test1929$DoThrowCatchTestException": Running breakpoint with handler "art.Test1929$ThrowBaseTestExceptionHandler"
-main: public static void art.Test1929.throwCatchTestException() @ line = 207 caught class art.Test1929$TestException: throwCatchTestException
+main: public static void art.Test1929.throwCatchTestException() @ line = 216 caught class art.Test1929$TestException: throwCatchTestException
Current Stack:
private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
private static void art.Test1929.PrintStack() @ line = 52
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
- public static void art.Test1929.throwCatchTestException() @ line = 207
- public void art.Test1929$DoThrowCatchTestException.run() @ line = 216
- public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+ public static void art.Test1929.throwCatchTestException() @ line = 216
+ public void art.Test1929$DoThrowCatchTestException.run() @ line = 225
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 295
Throwing BaseTestException!
-Test "art.Test1929$DoThrowCatchTestException": Caught error art.Test1929$BaseTestException:"ThrowBaseHandler during throw from public static void art.Test1929.throwCatchTestException() @ line = 207" with handler "art.Test1929$ThrowBaseTestExceptionHandler"
+Test "art.Test1929$DoThrowCatchTestException": Caught error art.Test1929$BaseTestException:"ThrowBaseHandler during throw from public static void art.Test1929.throwCatchTestException() @ line = 216" with handler "art.Test1929$ThrowBaseTestExceptionHandler"
Test "art.Test1929$DoThrowCatchTestException": Finished running with handler "art.Test1929$ThrowBaseTestExceptionHandler"
Test "art.Test1929$DoThrowCatchTestExceptionTwice": Running breakpoint with handler "art.Test1929$ThrowBaseTestExceptionHandler"
-main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 caught class art.Test1929$TestException: throwCatchTestExceptionTwice
+main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 175 caught class art.Test1929$TestException: throwCatchTestExceptionTwice
Current Stack:
private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
private static void art.Test1929.PrintStack() @ line = 52
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
- public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179
- public static void art.Test1929.throwCatchTestExceptionTwice() @ line = 222
- public void art.Test1929$DoThrowCatchTestExceptionTwice.run() @ line = 226
- public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+ public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 175
+ public static void art.Test1929.throwCatchTestExceptionTwice() @ line = 234
+ public void art.Test1929$DoThrowCatchTestExceptionTwice.run() @ line = 241
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 295
Caught art.Test1929$TestException: "throwCatchTestExceptionTwice"
Test "art.Test1929$DoThrowCatchTestExceptionTwice": No error caught with handler "art.Test1929$ThrowBaseTestExceptionHandler"
Test "art.Test1929$DoThrowCatchTestExceptionTwice": Finished running with handler "art.Test1929$ThrowBaseTestExceptionHandler"
Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Running breakpoint with handler "art.Test1929$ThrowBaseTestExceptionHandler"
-main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow
+main: public static void art.Test1929.run() throws java.lang.Exception @ line = 298 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow
Current Stack:
private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
private static void art.Test1929.PrintStack() @ line = 52
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
- public static void art.Test1929.run() throws java.lang.Exception @ line = 283
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 298
Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Caught error art.Test1929$TestException:"throwCatchTestExceptionNoRethrow" with handler "art.Test1929$ThrowBaseTestExceptionHandler"
Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Finished running with handler "art.Test1929$ThrowBaseTestExceptionHandler"
Test "art.Test1929$DoThrowClass": Running breakpoint with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
-main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: doThrow
+main: public static void art.Test1929.run() throws java.lang.Exception @ line = 298 caught class art.Test1929$TestException: doThrow
Current Stack:
private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
private static void art.Test1929.PrintStack() @ line = 52
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
- public static void art.Test1929.run() throws java.lang.Exception @ line = 283
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 298
Test "art.Test1929$DoThrowClass": Caught error art.Test1929$TestException:"doThrow" with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
Test "art.Test1929$DoThrowClass": Finished running with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
Test "art.Test1929$DoThrowCatchBaseTestException": Running breakpoint with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
@@ -245,58 +245,58 @@
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
public static void art.Test1929.throwCatchBaseTestException() @ line = 140
public void art.Test1929$DoThrowCatchBaseTestException.run() @ line = 149
- public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 295
Throwing TestExceptionNoRethrow!
Test "art.Test1929$DoThrowCatchBaseTestException": Caught error art.Test1929$TestExceptionNoRethrow:"ThrowTestExceptionNoRethrowHandler during throw from public static void art.Test1929.throwCatchBaseTestException() @ line = 140" with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
Test "art.Test1929$DoThrowCatchBaseTestException": Finished running with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Running breakpoint with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
-main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice
+main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 157 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice
Current Stack:
private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
private static void art.Test1929.PrintStack() @ line = 52
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
- public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161
- public static void art.Test1929.throwCatchBaseTestExceptionTwice() @ line = 197
- public void art.Test1929$DoThrowCatchBaseTestExceptionTwice.run() @ line = 201
- public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+ public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 157
+ public static void art.Test1929.throwCatchBaseTestExceptionTwice() @ line = 203
+ public void art.Test1929$DoThrowCatchBaseTestExceptionTwice.run() @ line = 210
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 295
Caught art.Test1929$TestException: "throwCatchBaseTestExceptionTwice"
Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": No error caught with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Finished running with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
Test "art.Test1929$DoThrowCatchTestException": Running breakpoint with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
-main: public static void art.Test1929.throwCatchTestException() @ line = 207 caught class art.Test1929$TestException: throwCatchTestException
+main: public static void art.Test1929.throwCatchTestException() @ line = 216 caught class art.Test1929$TestException: throwCatchTestException
Current Stack:
private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
private static void art.Test1929.PrintStack() @ line = 52
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
- public static void art.Test1929.throwCatchTestException() @ line = 207
- public void art.Test1929$DoThrowCatchTestException.run() @ line = 216
- public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+ public static void art.Test1929.throwCatchTestException() @ line = 216
+ public void art.Test1929$DoThrowCatchTestException.run() @ line = 225
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 295
Throwing TestExceptionNoRethrow!
-Test "art.Test1929$DoThrowCatchTestException": Caught error art.Test1929$TestExceptionNoRethrow:"ThrowTestExceptionNoRethrowHandler during throw from public static void art.Test1929.throwCatchTestException() @ line = 207" with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
+Test "art.Test1929$DoThrowCatchTestException": Caught error art.Test1929$TestExceptionNoRethrow:"ThrowTestExceptionNoRethrowHandler during throw from public static void art.Test1929.throwCatchTestException() @ line = 216" with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
Test "art.Test1929$DoThrowCatchTestException": Finished running with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
Test "art.Test1929$DoThrowCatchTestExceptionTwice": Running breakpoint with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
-main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 caught class art.Test1929$TestException: throwCatchTestExceptionTwice
+main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 175 caught class art.Test1929$TestException: throwCatchTestExceptionTwice
Current Stack:
private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
private static void art.Test1929.PrintStack() @ line = 52
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
- public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179
- public static void art.Test1929.throwCatchTestExceptionTwice() @ line = 222
- public void art.Test1929$DoThrowCatchTestExceptionTwice.run() @ line = 226
- public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+ public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 175
+ public static void art.Test1929.throwCatchTestExceptionTwice() @ line = 234
+ public void art.Test1929$DoThrowCatchTestExceptionTwice.run() @ line = 241
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 295
Caught art.Test1929$TestException: "throwCatchTestExceptionTwice"
Test "art.Test1929$DoThrowCatchTestExceptionTwice": No error caught with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
Test "art.Test1929$DoThrowCatchTestExceptionTwice": Finished running with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Running breakpoint with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
-main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow
+main: public static void art.Test1929.run() throws java.lang.Exception @ line = 298 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow
Current Stack:
private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
private static void art.Test1929.PrintStack() @ line = 52
public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
- public static void art.Test1929.run() throws java.lang.Exception @ line = 283
+ public static void art.Test1929.run() throws java.lang.Exception @ line = 298
Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Caught error art.Test1929$TestException:"throwCatchTestExceptionNoRethrow" with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Finished running with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
diff --git a/test/1929-exception-catch-exception/src/art/Test1929.java b/test/1929-exception-catch-exception/src/art/Test1929.java
index 07d2087..e2deb3f 100644
--- a/test/1929-exception-catch-exception/src/art/Test1929.java
+++ b/test/1929-exception-catch-exception/src/art/Test1929.java
@@ -152,49 +152,58 @@
// dx/d8/jack all do an optimization around catch blocks that (while legal) breaks assumptions
// this test relies on so we have the actual implementation be corrected smali. This does work
// for RI however.
- public static final class Impl {
- private Impl() {}
- public static void throwCatchBaseTestExceptionTwiceImpl() {
- try {
- try {
- throw new TestException("throwCatchBaseTestExceptionTwice");
- } catch (BaseTestException t) {
- System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\"");
- if (PRINT_FULL_EXCEPTION) {
- t.printStackTrace(System.out);
- }
- }
- } catch (BaseTestException t) {
- System.out.println("2nd Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\"");
- if (PRINT_FULL_EXCEPTION) {
- t.printStackTrace(System.out);
- }
- }
- }
- public static void throwCatchTestExceptionTwiceImpl() {
- try {
- try {
- throw new TestException("throwCatchTestExceptionTwice");
- } catch (TestException t) {
- System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\"");
- if (PRINT_FULL_EXCEPTION) {
- t.printStackTrace(System.out);
- }
- }
- } catch (TestException t) {
- System.out.println("2nd Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\"");
- if (PRINT_FULL_EXCEPTION) {
- t.printStackTrace(System.out);
- }
- }
- }
- }
+ // For reference:
+
+ // public static final class Impl {
+ // private Impl() {}
+ // public static void throwCatchBaseTestExceptionTwiceImpl() {
+ // try {
+ // try {
+ // throw new TestException("throwCatchBaseTestExceptionTwice");
+ // } catch (BaseTestException t) {
+ // System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\"");
+ // if (PRINT_FULL_EXCEPTION) {
+ // t.printStackTrace(System.out);
+ // }
+ // }
+ // } catch (BaseTestException t) {
+ // System.out.println("2nd Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\"");
+ // if (PRINT_FULL_EXCEPTION) {
+ // t.printStackTrace(System.out);
+ // }
+ // }
+ // }
+
+ // public static void throwCatchTestExceptionTwiceImpl() {
+ // try {
+ // try {
+ // throw new TestException("throwCatchTestExceptionTwice");
+ // } catch (TestException t) {
+ // System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\"");
+ // if (PRINT_FULL_EXCEPTION) {
+ // t.printStackTrace(System.out);
+ // }
+ // }
+ // } catch (TestException t) {
+ // System.out.println("2nd Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\"");
+ // if (PRINT_FULL_EXCEPTION) {
+ // t.printStackTrace(System.out);
+ // }
+ // }
+ // }
+ // }
public static void throwCatchBaseTestExceptionTwice() {
// The implementation of this has to change depending upon the runtime slightly due to compiler
// optimizations present in DX/D8/Jack.
- Impl.throwCatchBaseTestExceptionTwiceImpl();
+ try {
+ Class<?> Impl = Class.forName("art.Test1929$Impl");
+ Method m = Impl.getMethod("throwCatchBaseTestExceptionTwiceImpl");
+ m.invoke(null);
+ } catch (Exception e) {
+ e.printStackTrace(System.out);
+ }
}
public static class DoThrowCatchBaseTestExceptionTwice implements Runnable {
@@ -219,7 +228,13 @@
public static void throwCatchTestExceptionTwice() {
// The implementation of this has to change depending upon the runtime slightly due to compiler
// optimizations present in DX/D8/Jack.
- Impl.throwCatchTestExceptionTwiceImpl();
+ try {
+ Class<?> Impl = Class.forName("art.Test1929$Impl");
+ Method m = Impl.getMethod("throwCatchTestExceptionTwiceImpl");
+ m.invoke(null);
+ } catch (Exception e) {
+ e.printStackTrace(System.out);
+ }
}
public static class DoThrowCatchTestExceptionTwice implements Runnable {
diff --git a/test/674-hiddenapi/hiddenapi.cc b/test/674-hiddenapi/hiddenapi.cc
index effa37a..04c3fbf 100644
--- a/test/674-hiddenapi/hiddenapi.cc
+++ b/test/674-hiddenapi/hiddenapi.cc
@@ -16,6 +16,7 @@
#include "class_linker.h"
#include "dex/art_dex_file_loader.h"
+#include "hidden_api.h"
#include "jni.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
@@ -27,7 +28,7 @@
extern "C" JNIEXPORT void JNICALL Java_Main_init(JNIEnv*, jclass) {
Runtime* runtime = Runtime::Current();
- runtime->SetHiddenApiChecksEnabled(true);
+ runtime->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kBlacklistOnly);
runtime->SetDedupeHiddenApiWarnings(false);
runtime->AlwaysSetHiddenApiWarningFlag();
}
diff --git a/test/674-hiddenapi/src-ex/ChildClass.java b/test/674-hiddenapi/src-ex/ChildClass.java
index 8cd237a..582e907 100644
--- a/test/674-hiddenapi/src-ex/ChildClass.java
+++ b/test/674-hiddenapi/src-ex/ChildClass.java
@@ -123,9 +123,6 @@
// Check whether one can use an interface default method.
String name = "method" + visibility.name() + "Default" + hiddenness.name();
checkMethod(ParentInterface.class, name, /*isStatic*/ false, visibility, expected);
-
- // Check whether one can override this method.
- checkOverriding(suffix, isStatic, visibility, expected);
}
// Test whether static linking succeeds.
@@ -406,37 +403,6 @@
}
}
- private static void checkOverriding(String suffix,
- boolean isStatic,
- Visibility visibility,
- Behaviour behaviour) throws Exception {
- if (isStatic || visibility == Visibility.Private) {
- // Does not make sense to override a static or private method.
- return;
- }
-
- // The classes are in the same package, but will be able to access each
- // other only if loaded with the same class loader, here the boot class loader.
- boolean canAccess = (visibility != Visibility.Package) || (isParentInBoot && isChildInBoot);
- boolean setsWarning = false; // warnings may be set during vtable linking
-
- String methodName = "callMethod" + visibility.name() + suffix;
-
- // Force the test class to link its vtable, which may cause warnings, before
- // the actual test.
- new OverrideClass().methodPublicWhitelist();
-
- clearWarning();
- if (Linking.canOverride(methodName) != canAccess) {
- throw new RuntimeException("Expected to " + (canAccess ? "" : "not ") +
- "be able to override " + methodName + "." +
- "isParentInBoot = " + isParentInBoot + ", " + "isChildInBoot = " + isChildInBoot);
- }
- if (canAccess && hasPendingWarning() != setsWarning) {
- throwWarningException(ParentClass.class, methodName, false, "static linking", setsWarning);
- }
- }
-
private static void throwDiscoveryException(Class<?> klass, String name, boolean isField,
String fn, boolean canAccess) {
throw new RuntimeException("Expected " + (isField ? "field " : "method ") + klass.getName() +
diff --git a/test/674-hiddenapi/src-ex/Linking.java b/test/674-hiddenapi/src-ex/Linking.java
index b416250..a89b92b 100644
--- a/test/674-hiddenapi/src-ex/Linking.java
+++ b/test/674-hiddenapi/src-ex/Linking.java
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
public class Linking {
@@ -35,16 +34,6 @@
}
}
}
-
- public static boolean canOverride(String methodName) throws Exception {
- // ParentClass returns only positive numbers, OverrideClass only negative.
- // This way we can tell if OverrideClass managed to override the original
- // method or not.
- Method method = ParentClass.class.getDeclaredMethod(methodName);
- int result1 = (int) method.invoke(new ParentClass());
- int result2 = (int) method.invoke(new OverrideClass());
- return (result1 > 0) && (result2 < 0);
- }
}
// INSTANCE FIELD GET
diff --git a/test/674-hiddenapi/src-ex/OverrideClass.java b/test/674-hiddenapi/src-ex/OverrideClass.java
deleted file mode 100644
index 1f1f4d6..0000000
--- a/test/674-hiddenapi/src-ex/OverrideClass.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class OverrideClass extends ParentClass {
-
- @Override public int methodPublicWhitelist() { return -411; }
- @Override int methodPackageWhitelist() { return -412; }
- @Override protected int methodProtectedWhitelist() { return -413; }
-
- @Override public int methodPublicLightGreylist() { return -421; }
- @Override int methodPackageLightGreylist() { return -422; }
- @Override protected int methodProtectedLightGreylist() { return -423; }
-
- @Override public int methodPublicDarkGreylist() { return -431; }
- @Override int methodPackageDarkGreylist() { return -432; }
- @Override protected int methodProtectedDarkGreylist() { return -433; }
-
- @Override public int methodPublicBlacklist() { return -441; }
- @Override int methodPackageBlacklist() { return -442; }
- @Override protected int methodProtectedBlacklist() { return -443; }
-
-}
diff --git a/test/679-checker-minmax/src/Main.java b/test/679-checker-minmax/src/Main.java
index d016de6..38085bb 100644
--- a/test/679-checker-minmax/src/Main.java
+++ b/test/679-checker-minmax/src/Main.java
@@ -79,6 +79,51 @@
return a >= b ? b : a;
}
+ /// CHECK-START: int Main.min5(short, short) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Op1:s\d+>>,<<Op2:s\d+>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Op2>>,<<Op1>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.min5(short, short) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Min:i\d+>> Min
+ /// CHECK-DAG: Return [<<Min>>]
+ //
+ /// CHECK-START: int Main.min5(short, short) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static int min5(short a, short b) {
+ return a >= b ? b : a;
+ }
+
+ /// CHECK-START: int Main.min6(byte, byte) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Op1:b\d+>>,<<Op2:b\d+>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Op2>>,<<Op1>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.min6(byte, byte) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Min:i\d+>> Min
+ /// CHECK-DAG: Return [<<Min>>]
+ //
+ /// CHECK-START: int Main.min6(byte, byte) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static int min6(byte a, byte b) {
+ return a >= b ? b : a;
+ }
+
+ /// CHECK-START: long Main.min7(long, long) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Op1:j\d+>>,<<Op2:j\d+>>]
+ /// CHECK-DAG: <<Sel:j\d+>> Select [<<Op2>>,<<Op1>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: long Main.min7(long, long) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Min:j\d+>> Min
+ /// CHECK-DAG: Return [<<Min>>]
+ //
+ /// CHECK-START: long Main.min7(long, long) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static long min7(long a, long b) {
+ return a >= b ? b : a;
+ }
+
/// CHECK-START: int Main.max1(int, int) instruction_simplifier$after_inlining (before)
/// CHECK-DAG: <<Cnd:z\d+>> GreaterThanOrEqual [<<Op1:i\d+>>,<<Op2:i\d+>>]
/// CHECK-DAG: <<Sel:i\d+>> Select [<<Op2>>,<<Op1>>,<<Cnd>>]
@@ -139,15 +184,66 @@
return a >= b ? a : b;
}
+ /// CHECK-START: int Main.max5(short, short) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Op1:s\d+>>,<<Op2:s\d+>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Op1>>,<<Op2>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.max5(short, short) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Max:i\d+>> Max
+ /// CHECK-DAG: Return [<<Max>>]
+ //
+ /// CHECK-START: int Main.max5(short, short) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static int max5(short a, short b) {
+ return a >= b ? a : b;
+ }
+
+ /// CHECK-START: int Main.max6(byte, byte) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Op1:b\d+>>,<<Op2:b\d+>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Op1>>,<<Op2>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.max6(byte, byte) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Max:i\d+>> Max
+ /// CHECK-DAG: Return [<<Max>>]
+ //
+ /// CHECK-START: int Main.max6(byte, byte) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static int max6(byte a, byte b) {
+ return a >= b ? a : b;
+ }
+
+ /// CHECK-START: long Main.max7(long, long) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Op1:j\d+>>,<<Op2:j\d+>>]
+ /// CHECK-DAG: <<Sel:j\d+>> Select [<<Op1>>,<<Op2>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: long Main.max7(long, long) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Max:j\d+>> Max
+ /// CHECK-DAG: Return [<<Max>>]
+ //
+ /// CHECK-START: long Main.max7(long, long) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static long max7(long a, long b) {
+ return a >= b ? a : b;
+ }
+
public static void main(String[] args) {
expectEquals(10, min1(10, 20));
expectEquals(10, min2(10, 20));
expectEquals(10, min3(10, 20));
expectEquals(10, min4(10, 20));
+ expectEquals(10, min5((short) 10, (short) 20));
+ expectEquals(10, min6((byte) 10, (byte) 20));
+ expectEquals(10L, min7(10L, 20L));
expectEquals(20, max1(10, 20));
expectEquals(20, max2(10, 20));
expectEquals(20, max3(10, 20));
expectEquals(20, max4(10, 20));
+ expectEquals(20, max5((short) 10, (short) 20));
+ expectEquals(20, max6((byte) 10, (byte) 20));
+ expectEquals(20L, max7(10L, 20L));
System.out.println("passed");
}
@@ -156,4 +252,10 @@
throw new Error("Expected: " + expected + ", found: " + result);
}
}
+
+ private static void expectEquals(long expected, long result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
}
diff --git a/test/679-locks/expected.txt b/test/679-locks/expected.txt
new file mode 100644
index 0000000..85a20be
--- /dev/null
+++ b/test/679-locks/expected.txt
@@ -0,0 +1,2 @@
+JNI_OnLoad called
+MyString
diff --git a/test/679-locks/info.txt b/test/679-locks/info.txt
new file mode 100644
index 0000000..7ada490
--- /dev/null
+++ b/test/679-locks/info.txt
@@ -0,0 +1,2 @@
+Ensure FindLocksAtDexPc is able to pass through quickened instructions related
+to unresolved classes.
diff --git a/test/679-locks/run b/test/679-locks/run
new file mode 100644
index 0000000..0cc87f3
--- /dev/null
+++ b/test/679-locks/run
@@ -0,0 +1,18 @@
+#!/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.i
+
+# Run without an app image to prevent the class NotLoaded to be loaded at startup.
+exec ${RUN} "${@}" --no-app-image
diff --git a/test/679-locks/src/Main.java b/test/679-locks/src/Main.java
new file mode 100644
index 0000000..fbc8c53
--- /dev/null
+++ b/test/679-locks/src/Main.java
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+class NotLoaded {
+ public void foo() {}
+}
+
+public class Main {
+ public static void main(String[] args) throws Exception {
+ System.loadLibrary(args[0]);
+ TestSync.run();
+ }
+
+ public static void run() {
+ testVisitLocks();
+ }
+
+ static Object myStatic;
+
+ // Note: declared in 167-visit-locks.
+ public static native void testVisitLocks();
+}
+
+// 167-visit-locks/visit-locks.cc looks at the locks held in TestSync.run().
+class TestSync {
+ public static void run() {
+ Object o = Main.myStatic;
+ if (o != null) {
+ if (o instanceof NotLoaded) {
+ ((NotLoaded)o).foo();
+ }
+ }
+ synchronized ("MyString") {
+ Main.testVisitLocks();
+ }
+ }
+}
diff --git a/test/680-sink-regression/expected.txt b/test/680-sink-regression/expected.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/test/680-sink-regression/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/680-sink-regression/info.txt b/test/680-sink-regression/info.txt
new file mode 100644
index 0000000..547e3b8
--- /dev/null
+++ b/test/680-sink-regression/info.txt
@@ -0,0 +1 @@
+Regression test for code sinking with exceptions (b/75971227).
diff --git a/test/680-sink-regression/src/Main.java b/test/680-sink-regression/src/Main.java
new file mode 100644
index 0000000..642c3ab
--- /dev/null
+++ b/test/680-sink-regression/src/Main.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.*;
+
+/**
+ * Regression test for b/75971227 (code sinking with exceptions).
+ */
+public class Main {
+
+ public static class N {
+ int x;
+ }
+
+ private int f;
+
+ public int doit(N n1) throws FileNotFoundException {
+ int x = 1;
+ N n3 = new N();
+ try {
+ if (n1.x == 0) {
+ f = 11;
+ x = 3;
+ } else {
+ f = x;
+ }
+ throw new FileNotFoundException("n3" + n3.x);
+ } catch (NullPointerException e) {
+ }
+ return x;
+ }
+
+
+ public static void main(String[] args) {
+ N n = new N();
+ Main t = new Main();
+ int x = 0;
+
+ // Main 1, null pointer argument.
+ t.f = 0;
+ try {
+ x = t.doit(null);
+ } catch (FileNotFoundException e) {
+ x = -1;
+ }
+ if (x != 1 || t.f != 0) {
+ throw new Error("Main 1: x=" + x + " f=" + t.f);
+ }
+
+ // Main 2, n.x is 0.
+ n.x = 0;
+ try {
+ x = t.doit(n);
+ } catch (FileNotFoundException e) {
+ x = -1;
+ }
+ if (x != -1 || t.f != 11) {
+ throw new Error("Main 2: x=" + x + " f=" + t.f);
+ }
+
+ // Main 3, n.x is not 0.
+ n.x = 1;
+ try {
+ x = t.doit(n);
+ } catch (FileNotFoundException e) {
+ x = -1;
+ }
+ if (x != -1 || t.f != 1) {
+ throw new Error("Main 3: x=" + x + " f=" + t.f);
+ }
+
+ System.out.println("passed");
+ }
+}
diff --git a/test/681-checker-abs/expected.txt b/test/681-checker-abs/expected.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/test/681-checker-abs/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/681-checker-abs/info.txt b/test/681-checker-abs/info.txt
new file mode 100644
index 0000000..d36e76e
--- /dev/null
+++ b/test/681-checker-abs/info.txt
@@ -0,0 +1 @@
+Functional tests on detecting abs.
diff --git a/test/681-checker-abs/src/Main.java b/test/681-checker-abs/src/Main.java
new file mode 100644
index 0000000..8064b1d
--- /dev/null
+++ b/test/681-checker-abs/src/Main.java
@@ -0,0 +1,184 @@
+/*
+ * 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.
+ */
+
+/**
+ * Functional tests for detecting abs.
+ */
+public class Main {
+
+ /// CHECK-START: int Main.abs1(int) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0
+ /// CHECK-DAG: <<Cnd:z\d+>> GreaterThanOrEqual [<<Par>>,<<Zer>>]
+ /// CHECK-DAG: <<Neg:i\d+>> [<<Par>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Neg>>,<<Par>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.abs1(int) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Abs:i\d+>> Abs [<<Par>>]
+ /// CHECK-DAG: Return [<<Abs>>]
+ //
+ /// CHECK-START: int Main.abs1(int) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static int abs1(int a) {
+ return a < 0 ? -a : a;
+ }
+
+ /// CHECK-START: int Main.abs2(int) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0
+ /// CHECK-DAG: <<Cnd:z\d+>> GreaterThan [<<Par>>,<<Zer>>]
+ /// CHECK-DAG: <<Neg:i\d+>> [<<Par>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Neg>>,<<Par>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.abs2(int) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Abs:i\d+>> Abs [<<Par>>]
+ /// CHECK-DAG: Return [<<Abs>>]
+ //
+ /// CHECK-START: int Main.abs2(int) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static int abs2(int a) {
+ return a <= 0 ? -a : a;
+ }
+
+ /// CHECK-START: int Main.abs3(int) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThanOrEqual [<<Par>>,<<Zer>>]
+ /// CHECK-DAG: <<Neg:i\d+>> [<<Par>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Par>>,<<Neg>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.abs3(int) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Abs:i\d+>> Abs [<<Par>>]
+ /// CHECK-DAG: Return [<<Abs>>]
+ //
+ /// CHECK-START: int Main.abs3(int) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static int abs3(int a) {
+ return a > 0 ? a : -a;
+ }
+
+ /// CHECK-START: int Main.abs4(int) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Par>>,<<Zer>>]
+ /// CHECK-DAG: <<Neg:i\d+>> [<<Par>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Par>>,<<Neg>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.abs4(int) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Abs:i\d+>> Abs [<<Par>>]
+ /// CHECK-DAG: Return [<<Abs>>]
+ //
+ /// CHECK-START: int Main.abs4(int) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static int abs4(int a) {
+ return a >= 0 ? a : -a;
+ }
+
+ /// CHECK-START: int Main.abs5(short) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Par:s\d+>> ParameterValue
+ /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Par>>,<<Zer>>]
+ /// CHECK-DAG: <<Neg:i\d+>> [<<Par>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Par>>,<<Neg>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.abs5(short) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Par:s\d+>> ParameterValue
+ /// CHECK-DAG: <<Abs:i\d+>> Abs [<<Par>>]
+ /// CHECK-DAG: Return [<<Abs>>]
+ //
+ /// CHECK-START: int Main.abs5(short) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static int abs5(short a) {
+ return a >= 0 ? a : -a;
+ }
+
+ /// CHECK-START: int Main.abs6(byte) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Par:b\d+>> ParameterValue
+ /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Par>>,<<Zer>>]
+ /// CHECK-DAG: <<Neg:i\d+>> [<<Par>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Par>>,<<Neg>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.abs6(byte) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Par:b\d+>> ParameterValue
+ /// CHECK-DAG: <<Abs:i\d+>> Abs [<<Par>>]
+ /// CHECK-DAG: Return [<<Abs>>]
+ //
+ /// CHECK-START: int Main.abs6(byte) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static int abs6(byte a) {
+ return a >= 0 ? a : -a;
+ }
+
+ /// CHECK-START: long Main.abs7(long) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Par:j\d+>> ParameterValue
+ /// CHECK-DAG: <<Zer:j\d+>> LongConstant 0
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Par>>,<<Zer>>]
+ /// CHECK-DAG: <<Neg:j\d+>> [<<Par>>]
+ /// CHECK-DAG: <<Sel:j\d+>> Select [<<Par>>,<<Neg>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: long Main.abs7(long) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Par:j\d+>> ParameterValue
+ /// CHECK-DAG: <<Abs:j\d+>> Abs [<<Par>>]
+ /// CHECK-DAG: Return [<<Abs>>]
+ //
+ /// CHECK-START: long Main.abs7(long) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static long abs7(long a) {
+ return a >= 0 ? a : -a;
+ }
+
+ public static void main(String[] args) {
+ expectEquals(10, abs1(-10));
+ expectEquals(20, abs1(20));
+ expectEquals(10, abs2(-10));
+ expectEquals(20, abs2(20));
+ expectEquals(10, abs3(-10));
+ expectEquals(20, abs3(20));
+ expectEquals(10, abs4(-10));
+ expectEquals(20, abs4(20));
+ expectEquals(10, abs4((short) -10));
+ expectEquals(20, abs4((short) 20));
+ expectEquals(10, abs6((byte) -10));
+ expectEquals(20, abs6((byte) 20));
+ expectEquals(10L, abs7(-10L));
+ expectEquals(20L, abs7(20L));
+ System.out.println("passed");
+ }
+
+ private static void expectEquals(int expected, int result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
+ private static void expectEquals(long expected, long result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index cf781d7..6633958 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -24,7 +24,6 @@
$(HOST_OUT_EXECUTABLES)/hiddenapi \
$(HOST_OUT_EXECUTABLES)/jasmin \
$(HOST_OUT_EXECUTABLES)/smali \
- $(HOST_OUT_EXECUTABLES)/dexmerger \
$(HOST_OUT_JAVA_LIBRARIES)/desugar.jar
# Add d8 dependency, if enabled.
@@ -103,7 +102,7 @@
# Host executables.
host_prereq_rules := $(ART_TEST_HOST_RUN_TEST_DEPENDENCIES)
-# Required for dx, jasmin, smali, dexmerger.
+# Required for dx, jasmin, smali.
host_prereq_rules += $(TEST_ART_RUN_TEST_DEPENDENCIES)
# Sync test files to the target, depends upon all things that must be pushed
diff --git a/test/etc/default-build b/test/etc/default-build
index 3e6577c..9de7294 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -341,8 +341,26 @@
shift
done
- # Should have at least 1 dex_files_to_merge here, otherwise dxmerger will print the help.
- ${DXMERGER} "$dst_file" "${dex_files_to_merge[@]}"
+ # Skip merge if we are not merging anything. IE: input = output.
+ if [[ "${#dex_files_to_merge[@]}" -eq "1" ]]; then
+ local single_input=${dex_files_to_merge[0]}
+ if [[ "$dst_file" != "$single_input" ]]; then
+ mv "$single_input" "$dst_file";
+ return
+ fi
+ fi
+
+ # We assume the dexer did all the API level checks and just merge away.
+ mkdir d8_merge_out
+ ${DXMERGER} --min-api 1000 --output ./d8_merge_out "${dex_files_to_merge[@]}"
+
+ if [[ -e "./d8_merge_out/classes2.dex" ]]; then
+ echo "Cannot merge all dex files into a single dex"
+ exit 1
+ fi
+
+ mv ./d8_merge_out/classes.dex "$dst_file";
+ rmdir d8_merge_out
}
function make_hiddenapi() {
diff --git a/test/knownfailures.json b/test/knownfailures.json
index a7e76d1..22c370a 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -954,7 +954,8 @@
},
{
"tests": ["616-cha-unloading",
- "678-quickening"],
+ "678-quickening",
+ "679-locks"],
"variant": "jvm",
"description": ["Doesn't run on RI."]
},
diff --git a/test/run-test b/test/run-test
index 260a65a..5b43b52 100755
--- a/test/run-test
+++ b/test/run-test
@@ -50,11 +50,18 @@
export USE_DESUGAR="true"
export SMALI_ARGS=""
+# If d8 was not set by the environment variable, assume it is in the path.
+if [ -z "$D8" ]; then
+ export D8="d8"
+fi
+
# If dx was not set by the environment variable, assume it is in the path.
if [ -z "$DX" ]; then
export DX="dx"
fi
+export DXMERGER="$D8"
+
# If jasmin was not set by the environment variable, assume it is in the path.
if [ -z "$JASMIN" ]; then
export JASMIN="jasmin"
@@ -65,11 +72,6 @@
export SMALI="smali"
fi
-# If dexmerger was not set by the environment variable, assume it is in the path.
-if [ -z "$DXMERGER" ]; then
- export DXMERGER="dexmerger"
-fi
-
# If jack was not set by the environment variable, assume it is in the path.
if [ -z "$JACK" ]; then
export JACK="jack"
diff --git a/test/testrunner/env.py b/test/testrunner/env.py
index 70efce5..5394991 100644
--- a/test/testrunner/env.py
+++ b/test/testrunner/env.py
@@ -136,9 +136,8 @@
_get_build_var("HOST_OUT_EXECUTABLES"))
# Set up default values for $JACK, $DX, $SMALI, etc to the $HOST_OUT_EXECUTABLES/$name path.
-for tool in ['jack', 'dx', 'smali', 'jasmin', 'dxmerger']:
- binary = tool if tool != 'dxmerger' else 'dexmerger'
- os.environ.setdefault(tool.upper(), HOST_OUT_EXECUTABLES + '/' + binary)
+for tool in ['jack', 'dx', 'smali', 'jasmin', 'd8']:
+ os.environ.setdefault(tool.upper(), HOST_OUT_EXECUTABLES + '/' + tool)
ANDROID_JAVA_TOOLCHAIN = os.path.join(ANDROID_BUILD_TOP,
_get_build_var('ANDROID_JAVA_TOOLCHAIN'))
diff --git a/tools/ahat/Android.bp b/tools/ahat/Android.bp
new file mode 100644
index 0000000..dc9f098
--- /dev/null
+++ b/tools/ahat/Android.bp
@@ -0,0 +1,25 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// 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.
+
+droiddoc_host {
+ name: "ahat-docs",
+ srcs: [
+ "src/main/**/*.java",
+ ],
+ custom_template: "droiddoc-templates-sdk",
+ args: "-stubpackages com.android.ahat:com.android.ahat.*",
+ api_tag_name: "AHAT",
+ api_filename: "ahat_api.txt",
+ removed_api_filename: "ahat_removed_api.txt",
+}
diff --git a/tools/ahat/Android.mk b/tools/ahat/Android.mk
index bf79751..ad33233 100644
--- a/tools/ahat/Android.mk
+++ b/tools/ahat/Android.mk
@@ -37,23 +37,10 @@
include $(BUILD_HOST_JAVA_LIBRARY)
AHAT_JAR := $(LOCAL_BUILT_MODULE)
-AHAT_API := $(intermediates.COMMON)/ahat_api.txt
-AHAT_REMOVED_API := $(intermediates.COMMON)/ahat_removed_api.txt
# --- api check for ahat.jar ----------
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under, src/main)
-LOCAL_IS_HOST_MODULE := true
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-LOCAL_MODULE := ahat
-LOCAL_DROIDDOC_OPTIONS := \
- -stubpackages com.android.ahat:com.android.ahat.* \
- -api $(AHAT_API) \
- -removedApi $(AHAT_REMOVED_API)
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR := external/doclava/res/assets/templates-sdk
-include $(BUILD_DROIDDOC)
-$(AHAT_API): $(full_target)
+AHAT_API := $(INTERNAL_PLATFORM_AHAT_API_FILE)
+AHAT_REMOVED_API := $(INTERNAL_PLATFORM_AHAT_REMOVED_API_FILE)
$(eval $(call check-api, \
ahat-check-api, \