diff options
54 files changed, 1266 insertions, 693 deletions
diff --git a/compiler/optimizing/code_sinking.cc b/compiler/optimizing/code_sinking.cc index f4760d661f..2e31d35584 100644 --- a/compiler/optimizing/code_sinking.cc +++ b/compiler/optimizing/code_sinking.cc @@ -214,6 +214,11 @@ static HInstruction* FindIdealPosition(HInstruction* instruction, 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/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 9b370178f7..6950b93e51 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -1609,11 +1609,9 @@ class Dex2Oat FINAL { // 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 5590c8b3ab..5e9782aadf 100644 --- a/dex2oat/dex2oat_test.cc +++ b/dex2oat/dex2oat_test.cc @@ -2013,4 +2013,37 @@ TEST_F(Dex2oatTest, QuickenedInput) { 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_; +} + } // namespace art diff --git a/libdexfile/dex/dex_file_loader.cc b/libdexfile/dex/dex_file_loader.cc index 758a2f0599..1e0f5ac6ae 100644 --- a/libdexfile/dex/dex_file_loader.cc +++ b/libdexfile/dex/dex_file_loader.cc @@ -348,6 +348,8 @@ std::unique_ptr<DexFile> DexFileLoader::OpenCommon(const uint8_t* base, 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/runtime/class_linker.cc b/runtime/class_linker.cc index 8a29ff33b7..1d72b46f6c 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -5863,14 +5863,6 @@ bool ClassLinker::LinkVirtualMethods( // 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/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 7a0850d4b8..2284100564 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -2338,10 +2338,6 @@ extern "C" TwoWordReturn artQuickGenericJniTrampoline(Thread* self, ArtMethod** ArtMethod* called = *sp; DCHECK(called->IsNative()) << called->PrettyMethod(true); Runtime* runtime = Runtime::Current(); - jit::Jit* jit = runtime->GetJit(); - if (jit != nullptr) { - jit->AddSamples(self, called, 1u, /*with_backedges*/ false); - } uint32_t shorty_len = 0; const char* shorty = called->GetShorty(&shorty_len); bool critical_native = called->IsCriticalNative(); @@ -2367,6 +2363,12 @@ extern "C" TwoWordReturn artQuickGenericJniTrampoline(Thread* self, ArtMethod** self->VerifyStack(); + // We can now walk the stack if needed by JIT GC from MethodEntered() for JIT-on-first-use. + jit::Jit* jit = runtime->GetJit(); + if (jit != nullptr) { + jit->MethodEntered(self, called); + } + uint32_t cookie; uint32_t* sp32; // Skip calling JniMethodStart for @CriticalNative. diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h index 321d55d9b7..5c6b4b56bc 100644 --- a/runtime/hidden_api.h +++ b/runtime/hidden_api.h @@ -55,7 +55,6 @@ enum AccessMethod { kReflection, kJNI, kLinking, - kOverride, }; inline std::ostream& operator<<(std::ostream& os, AccessMethod value) { @@ -69,9 +68,6 @@ inline std::ostream& operator<<(std::ostream& os, AccessMethod value) { case kLinking: os << "linking"; break; - case kOverride: - os << "override"; - break; } return os; } diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc index 23cf071d56..813430f0bb 100644 --- a/runtime/jit/jit.cc +++ b/runtime/jit/jit.cc @@ -718,10 +718,11 @@ void Jit::MethodEntered(Thread* thread, ArtMethod* method) { Runtime* runtime = Runtime::Current(); if (UNLIKELY(runtime->UseJitCompilation() && runtime->GetJit()->JitAtFirstUse())) { ArtMethod* np_method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize); - DCHECK(!np_method->IsNative()); if (np_method->IsCompilable()) { - // The compiler requires a ProfilingInfo object. - ProfilingInfo::Create(thread, np_method, /* retry_allocation */ true); + if (!np_method->IsNative()) { + // The compiler requires a ProfilingInfo object for non-native methods. + ProfilingInfo::Create(thread, np_method, /* retry_allocation */ true); + } JitCompileTask compile_task(method, JitCompileTask::kCompile); compile_task.Run(thread); } diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc index fc9426650e..3692a308d8 100644 --- a/runtime/native/dalvik_system_VMDebug.cc +++ b/runtime/native/dalvik_system_VMDebug.cc @@ -89,17 +89,27 @@ static void VMDebug_resetAllocCount(JNIEnv*, jclass, jint kinds) { 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); -} - -static void VMDebug_startMethodTracingFd(JNIEnv* env, jclass, jstring javaTraceFilename, - jint javaFd, jint bufferSize, jint flags, - jboolean samplingEnabled, jint intervalUs, + Trace::StartDDMS(bufferSize, + flags, + samplingEnabled ? Trace::TraceMode::kSampling : Trace::TraceMode::kMethodTracing, + 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 @@ static void VMDebug_startMethodTracingFd(JNIEnv* env, jclass, jstring javaTraceF 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 @@ static void VMDebug_startMethodTracingFilename(JNIEnv* env, jclass, jstring java 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 cbc2aeb41f..d9a5096331 100644 --- a/runtime/native/dalvik_system_ZygoteHooks.cc +++ b/runtime/native/dalvik_system_ZygoteHooks.cc @@ -343,7 +343,6 @@ static void ZygoteHooks_nativePostForkChild(JNIEnv* env, 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, diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 53982ae833..9a626bab00 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -839,7 +839,6 @@ bool Runtime::Start() { 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, diff --git a/runtime/trace.cc b/runtime/trace.cc index 0f321b6591..91d2b3779e 100644 --- a/runtime/trace.cc +++ b/runtime/trace.cc @@ -319,8 +319,74 @@ void* Trace::RunSamplingThread(void* arg) { 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 @@ void Trace::Start(const char* trace_filename, int trace_fd, size_t buffer_size, 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 @@ void Trace::Start(const char* trace_filename, int trace_fd, size_t buffer_size, 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 @@ TracingMode Trace::GetMethodTracingMode() { 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 @@ Trace::Trace(File* trace_file, const char* trace_name, size_t buffer_size, int f 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 @@ Trace::Trace(File* trace_file, const char* trace_name, size_t buffer_size, int f 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 86b8d00d51..7171f759c9 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 @@ class Trace FINAL : public instrumentation::InstrumentationListener { 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 @@ class Trace FINAL : public instrumentation::InstrumentationListener { 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 @@ class Trace FINAL : public instrumentation::InstrumentationListener { 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 b07001e595..cee717610d 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -2765,47 +2765,61 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { 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 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { 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 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { } } 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 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { } } 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 @@ ArtMethod* MethodVerifier::VerifyInvocationArgsFromIterator( } } 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 @@ ArtMethod* MethodVerifier::VerifyInvocationArgsFromIterator( 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 @@ void MethodVerifier::VerifyInvocationArgsUnresolvedMethod(const Instruction* ins // 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 @@ ArtMethod* MethodVerifier::VerifyInvocationArgs( 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 @@ bool MethodVerifier::CheckSignaturePolymorphicReceiver(const Instruction* inst) 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); - } - - 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; +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; } - 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; + default: { + return inst->VRegB(); } - 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 @@ ArtField* MethodVerifier::GetInstanceField(const RegType& obj_type, int field_id 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 @@ void MethodVerifier::VerifyISFieldAccess(const Instruction* inst, const RegType& } } -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 9237a8b44b..531d3dabfa 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -209,12 +209,12 @@ class MethodVerifier { 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 field index of a field access instruction. + uint16_t GetFieldIdxOfFieldAccess(const Instruction* inst, bool is_static) 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_); uint32_t GetEncounteredFailureTypes() { return encountered_failure_types_; @@ -575,10 +575,6 @@ class MethodVerifier { 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 @@ class MethodVerifier { 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/test/121-modifiers/classes/A$B.class b/test/121-modifiers/classes/A$B.class Binary files differdeleted file mode 100644 index bd7ebfe11d..0000000000 --- a/test/121-modifiers/classes/A$B.class +++ /dev/null diff --git a/test/121-modifiers/classes/A$C.class b/test/121-modifiers/classes/A$C.class Binary files differdeleted file mode 100644 index 3ae872e356..0000000000 --- a/test/121-modifiers/classes/A$C.class +++ /dev/null diff --git a/test/121-modifiers/classes/A.class b/test/121-modifiers/classes/A.class Binary files differdeleted file mode 100644 index d89d029796..0000000000 --- a/test/121-modifiers/classes/A.class +++ /dev/null diff --git a/test/121-modifiers/classes/Inf.class b/test/121-modifiers/classes/Inf.class Binary files differdeleted file mode 100644 index e8dd68029d..0000000000 --- a/test/121-modifiers/classes/Inf.class +++ /dev/null diff --git a/test/121-modifiers/classes/Main.class b/test/121-modifiers/classes/Main.class Binary files differdeleted file mode 100644 index e044074269..0000000000 --- a/test/121-modifiers/classes/Main.class +++ /dev/null diff --git a/test/121-modifiers/classes/NonInf.class b/test/121-modifiers/classes/NonInf.class Binary files differdeleted file mode 100644 index 0f1e826fb7..0000000000 --- a/test/121-modifiers/classes/NonInf.class +++ /dev/null diff --git a/test/121-modifiers/info.txt b/test/121-modifiers/info.txt index 335df53f3d..7dba1133d1 100644 --- a/test/121-modifiers/info.txt +++ b/test/121-modifiers/info.txt @@ -10,9 +10,9 @@ Finally, compile with jack/jill or dx, and run baksmali. 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 0000000000..588854cf52 --- /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 2452490226..0000000000 --- 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 bc5608ac4e..a82b732eda 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 @@ main: public static void art.Test1929.throwCatchBaseTestException() @ line = 140 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 @@ main: public static void art.Test1929.throwCatchBaseTestException() @ line = 140 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 @@ main: public static void art.Test1929.throwCatchBaseTestException() @ line = 140 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 @@ main: public static void art.Test1929.throwCatchBaseTestException() @ line = 140 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 07d2087a0f..e2deb3f85f 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 @@ public class Test1929 { // 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 class Test1929 { 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/1935-get-set-current-frame-jit/expected.txt b/test/1935-get-set-current-frame-jit/expected.txt index fed993cc1a..cdb8f6a825 100644 --- a/test/1935-get-set-current-frame-jit/expected.txt +++ b/test/1935-get-set-current-frame-jit/expected.txt @@ -1,7 +1,7 @@ JNI_OnLoad called From GetLocalInt(), value is 42 -isInterpreted? true +isInOsrCode? false Value is '42' Setting TARGET to 1337 -isInterpreted? true +isInOsrCode? false Value is '1337' diff --git a/test/1935-get-set-current-frame-jit/src/Main.java b/test/1935-get-set-current-frame-jit/src/Main.java index eb0a6374d2..714a98aaf3 100644 --- a/test/1935-get-set-current-frame-jit/src/Main.java +++ b/test/1935-get-set-current-frame-jit/src/Main.java @@ -64,9 +64,9 @@ public class Main { Main.ensureJitCompiled(IntRunner.class, "run"); i++; } - // We shouldn't be doing OSR since we are using JVMTI and the get/set local will push us to - // interpreter. - System.out.println("isInterpreted? " + Main.isInterpreted()); + // We shouldn't be doing OSR since we are using JVMTI and the get/set prevents OSR. + // Set local will also push us to interpreter but the get local may remain in compiled code. + System.out.println("isInOsrCode? " + (hasJit() && Main.isInOsrCode("run"))); reportValue(TARGET); } public void waitForBusyLoopStart() { while (!inBusyLoop) {} } @@ -159,4 +159,6 @@ public class Main { public static native void ensureJitCompiled(Class k, String f); public static native boolean isInterpreted(); + public static native boolean isInOsrCode(String methodName); + public static native boolean hasJit(); } diff --git a/test/1940-ddms-ext/check b/test/1940-ddms-ext/check index d2c03841fc..91966b41a0 100755 --- a/test/1940-ddms-ext/check +++ b/test/1940-ddms-ext/check @@ -16,6 +16,6 @@ # Need to pull out the describeException ouput since that won't be there on # device. -sed -e '/\t.*$/d' "$2" | sed -e '/java.lang.ArrayIndexOutOfBoundsException:.*$/d' > "$2.tmp" +./remove_error.py "$2" "./expected_error.txt" > "$2.tmp" ./default-check "$1" "$2.tmp" diff --git a/test/1940-ddms-ext/expected_error.txt b/test/1940-ddms-ext/expected_error.txt new file mode 100644 index 0000000000..73883b46e2 --- /dev/null +++ b/test/1940-ddms-ext/expected_error.txt @@ -0,0 +1,4 @@ +java.lang.ArrayIndexOutOfBoundsException: byte[] offset=12 length=55 src.length=1 + at art.Test1940.processChunk(Native Method) + at art.Test1940.run(Test1940.java:156) + at Main.main(Main.java:19) diff --git a/test/1940-ddms-ext/remove_error.py b/test/1940-ddms-ext/remove_error.py new file mode 100755 index 0000000000..638c479a31 --- /dev/null +++ b/test/1940-ddms-ext/remove_error.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2018 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('input_data', type=open) + parser.add_argument('expected_error', type=str) + args = parser.parse_args() + + for line in map(str.rstrip, args.input_data.readlines()): + print_full = True + with open(args.expected_error) as err_file: + for err_line in map(str.rstrip, err_file): + if line.startswith(err_line): + print_full = False + if line != err_line: + print(line[len(err_line):]) + break + if print_full and line != '': + print(line) + +if __name__ == '__main__': + main() diff --git a/test/674-hiddenapi/src-ex/ChildClass.java b/test/674-hiddenapi/src-ex/ChildClass.java index 8cd237ab6f..582e907ca3 100644 --- a/test/674-hiddenapi/src-ex/ChildClass.java +++ b/test/674-hiddenapi/src-ex/ChildClass.java @@ -123,9 +123,6 @@ public class ChildClass { // 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 @@ public class ChildClass { } } - 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 b416250953..a89b92b2b9 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 class Linking { } } } - - 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 1f1f4d6aac..0000000000 --- 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-locks/expected.txt b/test/679-locks/expected.txt new file mode 100644 index 0000000000..85a20bea2f --- /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 0000000000..7ada4900c6 --- /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 0000000000..0cc87f3168 --- /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 0000000000..fbc8c53833 --- /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 0000000000..b0aad4deb5 --- /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 0000000000..547e3b801a --- /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 0000000000..642c3abdf4 --- /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/Android.run-test.mk b/test/Android.run-test.mk index cf781d7f2b..6633958140 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -24,7 +24,6 @@ TEST_ART_RUN_TEST_DEPENDENCIES := \ $(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 @@ endif # 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 3e6577cfda..9de7294a59 100755 --- a/test/etc/default-build +++ b/test/etc/default-build @@ -341,8 +341,26 @@ function make_dexmerge() { 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 a7e76d131e..22c370a61f 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 260a65a056..5b43b52b41 100755 --- a/test/run-test +++ b/test/run-test @@ -50,11 +50,18 @@ export USE_JACK="false" 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 @@ if [ -z "$SMALI" ]; then 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 70efce51ee..539499173c 100644 --- a/test/testrunner/env.py +++ b/test/testrunner/env.py @@ -136,9 +136,8 @@ HOST_OUT_EXECUTABLES = os.path.join(ANDROID_BUILD_TOP, _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/test/testrunner/testrunner.py b/test/testrunner/testrunner.py index a2215f9e9b..734a600c5e 100755 --- a/test/testrunner/testrunner.py +++ b/test/testrunner/testrunner.py @@ -114,6 +114,7 @@ ignore_skips = False build = False gdb = False gdb_arg = '' +runtime_option = '' stop_testrunner = False dex2oat_jobs = -1 # -1 corresponds to default threads for dex2oat run_all_configs = False @@ -346,6 +347,10 @@ def run_tests(tests): if gdb_arg: options_all += ' --gdb-arg ' + gdb_arg + if runtime_option: + for opt in runtime_option: + options_all += ' --runtime-option ' + opt + if dex2oat_jobs != -1: options_all += ' --dex2oat-jobs ' + str(dex2oat_jobs) @@ -921,6 +926,7 @@ def parse_option(): global build global gdb global gdb_arg + global runtime_option global timeout global dex2oat_jobs global run_all_configs @@ -933,9 +939,9 @@ def parse_option(): global_group.add_argument('--timeout', default=timeout, type=int, dest='timeout') global_group.add_argument('--verbose', '-v', action='store_true', dest='verbose') global_group.add_argument('--dry-run', action='store_true', dest='dry_run') - global_group.add_argument("--skip", action="append", dest="skips", default=[], + global_group.add_argument("--skip", action='append', dest="skips", default=[], help="Skip the given test in all circumstances.") - global_group.add_argument("--no-skips", dest="ignore_skips", action="store_true", default=False, + global_group.add_argument("--no-skips", dest="ignore_skips", action='store_true', default=False, help="""Don't skip any run-test configurations listed in knownfailures.json.""") global_group.add_argument('--no-build-dependencies', @@ -950,6 +956,10 @@ def parse_option(): global_group.set_defaults(build = env.ART_TEST_RUN_TEST_BUILD) global_group.add_argument('--gdb', action='store_true', dest='gdb') global_group.add_argument('--gdb-arg', dest='gdb_arg') + global_group.add_argument('--runtime-option', action='append', dest='runtime_option', + help="""Pass an option to the runtime. Runtime options + starting with a '-' must be separated by a '=', for + example '--runtime-option=-Xjitthreshold:0'.""") global_group.add_argument('--dex2oat-jobs', type=int, dest='dex2oat_jobs', help='Number of dex2oat jobs') global_group.add_argument('-a', '--all', action='store_true', dest='run_all', @@ -993,6 +1003,7 @@ def parse_option(): gdb = True if options['gdb_arg']: gdb_arg = options['gdb_arg'] + runtime_option = options['runtime_option']; timeout = options['timeout'] if options['dex2oat_jobs']: dex2oat_jobs = options['dex2oat_jobs'] diff --git a/tools/ahat/Android.bp b/tools/ahat/Android.bp new file mode 100644 index 0000000000..dc9f098ff3 --- /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 bf79751659..ad33233159 100644 --- a/tools/ahat/Android.mk +++ b/tools/ahat/Android.mk @@ -37,23 +37,10 @@ LOCAL_COMPATIBILITY_SUITE := general-tests 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, \ diff --git a/tools/veridex/Android.bp b/tools/veridex/Android.bp new file mode 100644 index 0000000000..31ff682828 --- /dev/null +++ b/tools/veridex/Android.bp @@ -0,0 +1,27 @@ +// Copyright (C) 2018 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +art_cc_binary { + name: "veridex", + host_supported: true, + srcs: [ + "resolver.cc", + "veridex.cc", + ], + cflags: ["-Wall", "-Werror"], + shared_libs: ["libdexfile", "libbase"], + header_libs: [ + "art_libartbase_headers", + ], +} diff --git a/tools/veridex/resolver.cc b/tools/veridex/resolver.cc new file mode 100644 index 0000000000..c0705e5ea8 --- /dev/null +++ b/tools/veridex/resolver.cc @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "resolver.h" + +#include "dex/dex_file-inl.h" +#include "dex/primitive.h" +#include "veridex.h" + +namespace art { + +void VeridexResolver::Run() { + size_t class_def_count = dex_file_.NumClassDefs(); + for (size_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) { + const DexFile::ClassDef& class_def = dex_file_.GetClassDef(class_def_index); + std::string name(dex_file_.StringByTypeIdx(class_def.class_idx_)); + auto existing = type_map_.find(name); + if (existing != type_map_.end()) { + // Class already exists, cache it and move on. + type_infos_[class_def.class_idx_.index_] = *existing->second; + continue; + } + type_infos_[class_def.class_idx_.index_] = VeriClass(Primitive::Type::kPrimNot, 0, &class_def); + type_map_[name] = &(type_infos_[class_def.class_idx_.index_]); + + const uint8_t* class_data = dex_file_.GetClassData(class_def); + if (class_data == nullptr) { + // Empty class. + continue; + } + + ClassDataItemIterator it(dex_file_, class_data); + for (; it.HasNextStaticField(); it.Next()) { + field_infos_[it.GetMemberIndex()] = it.DataPointer(); + } + for (; it.HasNextInstanceField(); it.Next()) { + field_infos_[it.GetMemberIndex()] = it.DataPointer(); + } + for (; it.HasNextMethod(); it.Next()) { + method_infos_[it.GetMemberIndex()] = it.DataPointer(); + } + } +} + +} // namespace art diff --git a/tools/veridex/resolver.h b/tools/veridex/resolver.h new file mode 100644 index 0000000000..4e0c5b3732 --- /dev/null +++ b/tools/veridex/resolver.h @@ -0,0 +1,46 @@ +/* + * 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. + */ + +#ifndef ART_TOOLS_VERIDEX_RESOLVER_H_ +#define ART_TOOLS_VERIDEX_RESOLVER_H_ + +#include "dex/dex_file.h" +#include "veridex.h" + +namespace art { + +class VeridexResolver { + public: + VeridexResolver(const DexFile& dex_file, TypeMap& type_map) + : dex_file_(dex_file), + type_map_(type_map), + type_infos_(dex_file.NumTypeIds(), VeriClass()), + method_infos_(dex_file.NumMethodIds(), nullptr), + field_infos_(dex_file.NumFieldIds(), nullptr) {} + + void Run(); + + private: + const DexFile& dex_file_; + TypeMap& type_map_; + std::vector<VeriClass> type_infos_; + std::vector<VeriMethod> method_infos_; + std::vector<VeriField> field_infos_; +}; + +} // namespace art + +#endif // ART_TOOLS_VERIDEX_RESOLVER_H_ diff --git a/tools/veridex/veridex.cc b/tools/veridex/veridex.cc new file mode 100644 index 0000000000..0370a0329c --- /dev/null +++ b/tools/veridex/veridex.cc @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "veridex.h" + +#include <android-base/file.h> + +#include "dex/dex_file.h" +#include "dex/dex_file_loader.h" +#include "resolver.h" + +#include <sstream> + +namespace art { + +struct VeridexOptions { + const char* dex_file = nullptr; + const char* core_stubs = nullptr; + const char* blacklist = nullptr; + const char* light_greylist = nullptr; + const char* dark_greylist = nullptr; +}; + +static const char* Substr(const char* str, int index) { + return str + index; +} + +static bool StartsWith(const char* str, const char* val) { + return strlen(str) >= strlen(val) && memcmp(str, val, strlen(val)) == 0; +} + +static void ParseArgs(VeridexOptions* options, int argc, char** argv) { + // Skip over the command name. + argv++; + argc--; + + static const char* kDexFileOption = "--dex-file="; + static const char* kStubsOption = "--core-stubs="; + static const char* kBlacklistOption = "--blacklist="; + static const char* kDarkGreylistOption = "--dark-greylist="; + static const char* kLightGreylistOption = "--light-greylist="; + + for (int i = 0; i < argc; ++i) { + if (StartsWith(argv[i], kDexFileOption)) { + options->dex_file = Substr(argv[i], strlen(kDexFileOption)); + } else if (StartsWith(argv[i], kStubsOption)) { + options->core_stubs = Substr(argv[i], strlen(kStubsOption)); + } else if (StartsWith(argv[i], kBlacklistOption)) { + options->blacklist = Substr(argv[i], strlen(kBlacklistOption)); + } else if (StartsWith(argv[i], kDarkGreylistOption)) { + options->dark_greylist = Substr(argv[i], strlen(kDarkGreylistOption)); + } else if (StartsWith(argv[i], kLightGreylistOption)) { + options->light_greylist = Substr(argv[i], strlen(kLightGreylistOption)); + } + } +} + +static std::vector<std::string> Split(const std::string& str, char sep) { + std::vector<std::string> tokens; + std::string tmp; + std::istringstream iss(str); + while (std::getline(iss, tmp, sep)) { + tokens.push_back(tmp); + } + return tokens; +} + +class Veridex { + public: + static int Run(int argc, char** argv) { + VeridexOptions options; + ParseArgs(&options, argc, argv); + + std::vector<std::string> boot_content; + std::vector<std::string> app_content; + std::vector<std::unique_ptr<const DexFile>> boot_dex_files; + std::vector<std::unique_ptr<const DexFile>> app_dex_files; + std::string error_msg; + + // Read the boot classpath. + std::vector<std::string> boot_classpath = Split(options.core_stubs, ':'); + boot_content.resize(boot_classpath.size()); + uint32_t i = 0; + for (const std::string& str : boot_classpath) { + if (!Load(str, boot_content[i++], &boot_dex_files, &error_msg)) { + LOG(ERROR) << error_msg; + return 1; + } + } + + // Read the apps dex files. + std::vector<std::string> app_files = Split(options.dex_file, ':'); + app_content.resize(app_files.size()); + i = 0; + for (const std::string& str : app_files) { + if (!Load(str, app_content[i++], &app_dex_files, &error_msg)) { + LOG(ERROR) << error_msg; + return 1; + } + } + + // Resolve classes/methods/fields defined in each dex file. + + // Cache of types we've seen. This is used in case of duplicate classes. + TypeMap type_map; + + std::vector<VeridexResolver> boot_resolvers; + Resolve(boot_dex_files, type_map, &boot_resolvers); + + std::vector<VeridexResolver> app_resolvers; + Resolve(app_dex_files, type_map, &app_resolvers); + + return 0; + } + + private: + static bool Load(const std::string& filename, + std::string& content, + std::vector<std::unique_ptr<const DexFile>>* dex_files, + std::string* error_msg) { + if (filename.empty()) { + *error_msg = "Missing file name"; + return false; + } + + // TODO: once added, use an api to android::base to read a std::vector<uint8_t>. + if (!android::base::ReadFileToString(filename.c_str(), &content)) { + *error_msg = "ReadFileToString failed for " + filename; + return false; + } + + const DexFileLoader dex_file_loader; + static constexpr bool kVerifyChecksum = true; + static constexpr bool kRunDexFileVerifier = true; + if (!dex_file_loader.OpenAll(reinterpret_cast<const uint8_t*>(content.data()), + content.size(), + filename.c_str(), + kRunDexFileVerifier, + kVerifyChecksum, + error_msg, + dex_files)) { + return false; + } + + return true; + } + + static void Resolve(const std::vector<std::unique_ptr<const DexFile>>& dex_files, + TypeMap& type_map, + std::vector<VeridexResolver>* resolvers) { + for (const std::unique_ptr<const DexFile>& dex_file : dex_files) { + resolvers->push_back(VeridexResolver(*dex_file.get(), type_map)); + } + + for (VeridexResolver& resolver : *resolvers) { + resolver.Run(); + } + } +}; + +} // namespace art + +int main(int argc, char** argv) { + return art::Veridex::Run(argc, argv); +} + diff --git a/tools/veridex/veridex.h b/tools/veridex/veridex.h new file mode 100644 index 0000000000..bbff254f0a --- /dev/null +++ b/tools/veridex/veridex.h @@ -0,0 +1,72 @@ +/* + * 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. + */ + +#ifndef ART_TOOLS_VERIDEX_VERIDEX_H_ +#define ART_TOOLS_VERIDEX_VERIDEX_H_ + +#include <map> + +#include "dex/dex_file.h" +#include "dex/primitive.h" + +namespace art { + +/** + * Abstraction for classes defined, or implicitly defined (for arrays and primitives) + * in dex files. + */ +class VeriClass { + public: + VeriClass(const VeriClass& other) = default; + VeriClass() = default; + VeriClass(Primitive::Type k, uint8_t dims, const DexFile::ClassDef* cl) + : kind_(k), dimensions_(dims), class_def_(cl) {} + + bool IsUninitialized() const { + return kind_ == Primitive::Type::kPrimNot && dimensions_ == 0 && class_def_ == nullptr; + } + + bool IsPrimitive() const { + return kind_ != Primitive::Type::kPrimNot && dimensions_ == 0; + } + + bool IsArray() const { + return dimensions_ != 0; + } + + private: + Primitive::Type kind_; + uint8_t dimensions_; + const DexFile::ClassDef* class_def_; +}; + +/** + * Abstraction for fields defined in dex files. Currently, that's a pointer into their + * `encoded_field` description. + */ +using VeriField = const uint8_t*; + +/** + * Abstraction for methods defined in dex files. Currently, that's a pointer into their + * `encoded_method` description. + */ +using VeriMethod = const uint8_t*; + +using TypeMap = std::map<std::string, VeriClass*>; + +} // namespace art + +#endif // ART_TOOLS_VERIDEX_VERIDEX_H_ |