summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/Android.common_build.mk21
-rw-r--r--build/Android.oat.mk6
-rw-r--r--compiler/dex/quick/codegen_util.cc4
-rw-r--r--compiler/dex/verification_results.cc9
-rw-r--r--compiler/dex/verification_results.h1
-rw-r--r--compiler/driver/compiler_driver.cc42
-rw-r--r--compiler/driver/compiler_driver.h4
-rw-r--r--compiler/driver/dex_compilation_unit.h6
-rw-r--r--compiler/image_writer.cc7
-rw-r--r--compiler/optimizing/builder.cc5
-rw-r--r--compiler/optimizing/code_generator.h3
-rw-r--r--compiler/optimizing/code_generator_arm.cc16
-rw-r--r--compiler/optimizing/code_generator_x86.cc32
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc32
-rw-r--r--compiler/optimizing/nodes.cc57
-rw-r--r--compiler/optimizing/nodes.h1
-rw-r--r--dex2oat/dex2oat.cc29
-rw-r--r--test/004-JniTest/jni_test.cc20
-rw-r--r--test/422-type-conversion/src/Main.java32
-rw-r--r--test/435-try-finally-without-catch/expected.txt3
-rw-r--r--test/435-try-finally-without-catch/info.txt26
-rw-r--r--test/435-try-finally-without-catch/src/Main.java41
-rw-r--r--test/Android.run-test.mk1
-rwxr-xr-xtest/run-test4
24 files changed, 336 insertions, 66 deletions
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index 5dd9f1534c..63469703f2 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -259,16 +259,21 @@ ifeq ($(HOST_OS),linux)
art_target_non_debug_cflags += -Wframe-larger-than=1728
endif
-ifndef LIBART_IMG_HOST_BASE_ADDRESS
- $(error LIBART_IMG_HOST_BASE_ADDRESS unset)
-endif
-ART_HOST_CFLAGS += $(art_cflags) -DART_BASE_ADDRESS=$(LIBART_IMG_HOST_BASE_ADDRESS)
-ART_HOST_CFLAGS += -DART_DEFAULT_INSTRUCTION_SET_FEATURES=default
+# DALVIK_VM_LIB will be empty for VM-less builds. Avoid $(error) calls here because
+# LIBART_IMG_XXX variables won't be defined.
+ifneq ($(DALVIK_VM_LIB),)
+ ifndef LIBART_IMG_HOST_BASE_ADDRESS
+ $(error LIBART_IMG_HOST_BASE_ADDRESS unset)
+ endif
+ ART_HOST_CFLAGS += $(art_cflags) -DART_BASE_ADDRESS=$(LIBART_IMG_HOST_BASE_ADDRESS)
+ ART_HOST_CFLAGS += -DART_DEFAULT_INSTRUCTION_SET_FEATURES=default
-ifndef LIBART_IMG_TARGET_BASE_ADDRESS
- $(error LIBART_IMG_TARGET_BASE_ADDRESS unset)
+ ifndef LIBART_IMG_TARGET_BASE_ADDRESS
+ $(error LIBART_IMG_TARGET_BASE_ADDRESS unset)
+ endif
+ ART_TARGET_CFLAGS += $(art_cflags) \
+ -DART_TARGET -DART_BASE_ADDRESS=$(LIBART_IMG_TARGET_BASE_ADDRESS)
endif
-ART_TARGET_CFLAGS += $(art_cflags) -DART_TARGET -DART_BASE_ADDRESS=$(LIBART_IMG_TARGET_BASE_ADDRESS)
ART_HOST_NON_DEBUG_CFLAGS := $(art_host_non_debug_cflags)
ART_TARGET_NON_DEBUG_CFLAGS := $(art_target_non_debug_cflags)
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index e8b363ba26..523d14345c 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -44,6 +44,9 @@ define create-core-oat-host-rules
core_pic_infix :=
core_dex2oat_dependency := $(DEX2OAT_DEPENDENCY)
+ ifeq ($(1),default)
+ core_compile_options += --compiler-backend=Quick
+ endif
ifeq ($(1),optimizing)
core_compile_options += --compiler-backend=Optimizing
# With the optimizing compiler, we want to rerun dex2oat whenever there is
@@ -137,6 +140,9 @@ define create-core-oat-target-rules
core_pic_infix :=
core_dex2oat_dependency := $(DEX2OAT_DEPENDENCY)
+ ifeq ($(1),default)
+ core_compile_options += --compiler-backend=Quick
+ endif
ifeq ($(1),optimizing)
ifeq ($($(3)TARGET_ARCH),arm64)
# TODO: Enable image generation on arm64 once the backend
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 58bcee2124..00217549b0 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -775,6 +775,10 @@ void Mir2Lir::CreateNativeGcMap() {
": " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
native_gc_map_builder.AddEntry(native_offset, references);
}
+
+ // Maybe not necessary, but this could help prevent errors where we access the verified method
+ // after it has been deleted.
+ mir_graph_->GetCurrentDexCompilationUnit()->ClearVerifiedMethod();
}
/* Determine the offset of each literal field */
diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc
index 4929b5b2b0..932a532e56 100644
--- a/compiler/dex/verification_results.cc
+++ b/compiler/dex/verification_results.cc
@@ -84,6 +84,15 @@ const VerifiedMethod* VerificationResults::GetVerifiedMethod(MethodReference ref
return (it != verified_methods_.end()) ? it->second : nullptr;
}
+void VerificationResults::RemoveVerifiedMethod(MethodReference ref) {
+ WriterMutexLock mu(Thread::Current(), verified_methods_lock_);
+ auto it = verified_methods_.find(ref);
+ if (it != verified_methods_.end()) {
+ delete it->second;
+ verified_methods_.erase(it);
+ }
+}
+
void VerificationResults::AddRejectedClass(ClassReference ref) {
{
WriterMutexLock mu(Thread::Current(), rejected_classes_lock_);
diff --git a/compiler/dex/verification_results.h b/compiler/dex/verification_results.h
index 0e7923fbc3..7fc2a2363d 100644
--- a/compiler/dex/verification_results.h
+++ b/compiler/dex/verification_results.h
@@ -48,6 +48,7 @@ class VerificationResults {
const VerifiedMethod* GetVerifiedMethod(MethodReference ref)
LOCKS_EXCLUDED(verified_methods_lock_);
+ void RemoveVerifiedMethod(MethodReference ref) LOCKS_EXCLUDED(verified_methods_lock_);
void AddRejectedClass(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_);
bool IsClassRejected(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_);
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index ab9f41a4b3..e4274712d4 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -23,6 +23,10 @@
#include <vector>
#include <unistd.h>
+#ifndef __APPLE__
+#include <malloc.h> // For mallinfo
+#endif
+
#include "base/stl_util.h"
#include "base/timing_logger.h"
#include "class_linker.h"
@@ -497,6 +501,7 @@ void CompilerDriver::CompileAll(jobject class_loader,
TimingLogger* timings) {
DCHECK(!Runtime::Current()->IsStarted());
std::unique_ptr<ThreadPool> thread_pool(new ThreadPool("Compiler driver thread pool", thread_count_ - 1));
+ VLOG(compiler) << "Before precompile " << GetMemoryUsageString();
PreCompile(class_loader, dex_files, thread_pool.get(), timings);
Compile(class_loader, dex_files, thread_pool.get(), timings);
if (dump_stats_) {
@@ -593,20 +598,25 @@ void CompilerDriver::Resolve(jobject class_loader, const std::vector<const DexFi
void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
ThreadPool* thread_pool, TimingLogger* timings) {
LoadImageClasses(timings);
+ VLOG(compiler) << "LoadImageClasses: " << GetMemoryUsageString();
Resolve(class_loader, dex_files, thread_pool, timings);
+ VLOG(compiler) << "Resolve: " << GetMemoryUsageString();
if (!compiler_options_->IsVerificationEnabled()) {
- LOG(INFO) << "Verify none mode specified, skipping verification.";
+ VLOG(compiler) << "Verify none mode specified, skipping verification.";
SetVerified(class_loader, dex_files, thread_pool, timings);
return;
}
Verify(class_loader, dex_files, thread_pool, timings);
+ VLOG(compiler) << "Verify: " << GetMemoryUsageString();
InitializeClasses(class_loader, dex_files, thread_pool, timings);
+ VLOG(compiler) << "InitializeClasses: " << GetMemoryUsageString();
UpdateImageClasses(timings);
+ VLOG(compiler) << "UpdateImageClasses: " << GetMemoryUsageString();
}
bool CompilerDriver::IsImageClass(const char* descriptor) const {
@@ -2002,6 +2012,7 @@ void CompilerDriver::Compile(jobject class_loader, const std::vector<const DexFi
CHECK(dex_file != nullptr);
CompileDexFile(class_loader, *dex_file, dex_files, thread_pool, timings);
}
+ VLOG(compiler) << "Compile: " << GetMemoryUsageString();
}
void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, size_t class_def_index) {
@@ -2128,6 +2139,7 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t
bool compilation_enabled) {
CompiledMethod* compiled_method = nullptr;
uint64_t start_ns = kTimeCompileMethod ? NanoTime() : 0;
+ MethodReference method_ref(&dex_file, method_idx);
if ((access_flags & kAccNative) != 0) {
// Are we interpreting only and have support for generic JNI down calls?
@@ -2141,7 +2153,6 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t
} else if ((access_flags & kAccAbstract) != 0) {
// Abstract methods don't have code.
} else {
- MethodReference method_ref(&dex_file, method_idx);
bool compile = compilation_enabled &&
verification_results_->IsCandidateForCompilation(method_ref, access_flags);
if (compile) {
@@ -2178,16 +2189,18 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t
// When compiling with PIC, there should be zero non-relative linker patches
CHECK(!compile_pic || non_relative_linker_patch_count == 0u);
- MethodReference ref(&dex_file, method_idx);
- DCHECK(GetCompiledMethod(ref) == nullptr) << PrettyMethod(method_idx, dex_file);
+ DCHECK(GetCompiledMethod(method_ref) == nullptr) << PrettyMethod(method_idx, dex_file);
{
MutexLock mu(self, compiled_methods_lock_);
- compiled_methods_.Put(ref, compiled_method);
+ compiled_methods_.Put(method_ref, compiled_method);
non_relative_linker_patch_count_ += non_relative_linker_patch_count;
}
- DCHECK(GetCompiledMethod(ref) != nullptr) << PrettyMethod(method_idx, dex_file);
+ DCHECK(GetCompiledMethod(method_ref) != nullptr) << PrettyMethod(method_idx, dex_file);
}
+ // Done compiling, delete the verified method to reduce native memory usage.
+ verification_results_->RemoveVerifiedMethod(method_ref);
+
if (self->IsExceptionPending()) {
ScopedObjectAccess soa(self);
LOG(FATAL) << "Unexpected exception compiling: " << PrettyMethod(method_idx, dex_file) << "\n"
@@ -2337,4 +2350,21 @@ bool CompilerDriver::SkipCompilation(const std::string& method_name) {
}
return !compile;
}
+
+std::string CompilerDriver::GetMemoryUsageString() const {
+ std::ostringstream oss;
+ const ArenaPool* arena_pool = GetArenaPool();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
+ oss << "arena alloc=" << PrettySize(arena_pool->GetBytesAllocated());
+ oss << " java alloc=" << PrettySize(heap->GetBytesAllocated());
+#ifdef HAVE_MALLOC_H
+ struct mallinfo info = mallinfo();
+ const size_t allocated_space = static_cast<size_t>(info.uordblks);
+ const size_t free_space = static_cast<size_t>(info.fordblks);
+ oss << " native alloc=" << PrettySize(allocated_space) << " free="
+ << PrettySize(free_space);
+#endif
+ return oss.str();
+}
+
} // namespace art
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index d837dbc9cd..615e0d0db4 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -39,6 +39,7 @@
#include "thread_pool.h"
#include "utils/arena_allocator.h"
#include "utils/dedupe_set.h"
+#include "dex/verified_method.h"
namespace art {
@@ -398,6 +399,9 @@ class CompilerDriver {
// Should the compiler run on this method given profile information?
bool SkipCompilation(const std::string& method_name);
+ // Get memory usage during compilation.
+ std::string GetMemoryUsageString() const;
+
private:
// These flags are internal to CompilerDriver for collecting INVOKE resolution statistics.
// The only external contract is that unresolved method has flags 0 and resolved non-0.
diff --git a/compiler/driver/dex_compilation_unit.h b/compiler/driver/dex_compilation_unit.h
index 84f57991c3..03ae489da1 100644
--- a/compiler/driver/dex_compilation_unit.h
+++ b/compiler/driver/dex_compilation_unit.h
@@ -102,6 +102,10 @@ class DexCompilationUnit {
return verified_method_;
}
+ void ClearVerifiedMethod() {
+ verified_method_ = nullptr;
+ }
+
const std::string& GetSymbol();
private:
@@ -117,7 +121,7 @@ class DexCompilationUnit {
const uint16_t class_def_idx_;
const uint32_t dex_method_idx_;
const uint32_t access_flags_;
- const VerifiedMethod* const verified_method_;
+ const VerifiedMethod* verified_method_;
std::string symbol_;
};
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 3b1d914f6e..ab5c6c77de 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -77,6 +77,7 @@ bool ImageWriter::PrepareImageAddressSpace() {
Thread::Current()->TransitionFromSuspendedToRunnable();
PruneNonImageClasses(); // Remove junk
ComputeLazyFieldsForImageClasses(); // Add useful information
+ ProcessStrings();
Thread::Current()->TransitionFromRunnableToSuspended(kNative);
}
gc::Heap* heap = Runtime::Current()->GetHeap();
@@ -561,9 +562,9 @@ void ImageWriter::ProcessStrings() {
bool is_prefix = false;
if (it != existing_strings.end()) {
CHECK_LE(length, it->second);
- is_prefix = std::equal(combined_chars.begin() + it->first,
- combined_chars.begin() + it->first + it->second,
- combined_chars.begin() + new_string.first);
+ is_prefix = std::equal(combined_chars.begin() + new_string.first,
+ combined_chars.begin() + new_string.first + new_string.second,
+ combined_chars.begin() + it->first);
}
if (is_prefix) {
// Shares a prefix, set the offset to where the new offset will be.
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 23c3b390c0..eb6181c711 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -1108,6 +1108,11 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
break;
}
+ case Instruction::FLOAT_TO_INT: {
+ Conversion_12x(instruction, Primitive::kPrimFloat, Primitive::kPrimInt);
+ break;
+ }
+
case Instruction::INT_TO_BYTE: {
Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimByte);
break;
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 4c0d3ea960..7c8f6a2d29 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -35,6 +35,9 @@ static int64_t constexpr k2Pow32EncodingForDouble = INT64_C(0x41F0000000000000);
// Binary encoding of 2^31 for type double.
static int64_t constexpr k2Pow31EncodingForDouble = INT64_C(0x41E0000000000000);
+// Maximum value for a primitive integer.
+static int32_t constexpr kPrimIntMax = 0x7fffffff;
+
class Assembler;
class CodeGenerator;
class DexCompilationUnit;
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 5b2be2e9a1..448a5a0707 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1406,6 +1406,12 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
break;
case Primitive::kPrimFloat:
+ // Processing a Dex `float-to-int' instruction.
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresFpuRegister());
+ break;
+
case Primitive::kPrimDouble:
LOG(FATAL) << "Type conversion from " << input_type
<< " to " << result_type << " not yet implemented";
@@ -1580,7 +1586,15 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio
}
break;
- case Primitive::kPrimFloat:
+ case Primitive::kPrimFloat: {
+ // Processing a Dex `float-to-int' instruction.
+ SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
+ __ vmovs(temp, in.AsFpuRegister<SRegister>());
+ __ vcvtis(temp, temp);
+ __ vmovrs(out.AsRegister<Register>(), temp);
+ break;
+ }
+
case Primitive::kPrimDouble:
LOG(FATAL) << "Type conversion from " << input_type
<< " to " << result_type << " not yet implemented";
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index fd794f95d1..6f83d9faf4 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1373,6 +1373,12 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
break;
case Primitive::kPrimFloat:
+ // Processing a Dex `float-to-int' instruction.
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresFpuRegister());
+ break;
+
case Primitive::kPrimDouble:
LOG(FATAL) << "Type conversion from " << input_type
<< " to " << result_type << " not yet implemented";
@@ -1559,7 +1565,31 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio
}
break;
- case Primitive::kPrimFloat:
+ case Primitive::kPrimFloat: {
+ // Processing a Dex `float-to-int' instruction.
+ XmmRegister input = in.AsFpuRegister<XmmRegister>();
+ Register output = out.AsRegister<Register>();
+ XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
+ Label done, nan;
+
+ __ movl(output, Immediate(kPrimIntMax));
+ // temp = int-to-float(output)
+ __ cvtsi2ss(temp, output);
+ // if input >= temp goto done
+ __ comiss(input, temp);
+ __ j(kAboveEqual, &done);
+ // if input == NaN goto nan
+ __ j(kUnordered, &nan);
+ // output = float-to-int-truncate(input)
+ __ cvttss2si(output, input);
+ __ jmp(&done);
+ __ Bind(&nan);
+ // output = 0
+ __ xorl(output, output);
+ __ Bind(&done);
+ break;
+ }
+
case Primitive::kPrimDouble:
LOG(FATAL) << "Type conversion from " << input_type
<< " to " << result_type << " not yet implemented";
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 4d70efcf38..47fd304969 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1363,6 +1363,12 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
break;
case Primitive::kPrimFloat:
+ // Processing a Dex `float-to-int' instruction.
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresFpuRegister());
+ break;
+
case Primitive::kPrimDouble:
LOG(FATAL) << "Type conversion from " << input_type
<< " to " << result_type << " not yet implemented";
@@ -1550,7 +1556,31 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
}
break;
- case Primitive::kPrimFloat:
+ case Primitive::kPrimFloat: {
+ // Processing a Dex `float-to-int' instruction.
+ XmmRegister input = in.AsFpuRegister<XmmRegister>();
+ CpuRegister output = out.AsRegister<CpuRegister>();
+ XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
+ Label done, nan;
+
+ __ movl(output, Immediate(kPrimIntMax));
+ // temp = int-to-float(output)
+ __ cvtsi2ss(temp, output);
+ // if input >= temp goto done
+ __ comiss(input, temp);
+ __ j(kAboveEqual, &done);
+ // if input == NaN goto nan
+ __ j(kUnordered, &nan);
+ // output = float-to-int-truncate(input)
+ __ cvttss2si(output, input);
+ __ jmp(&done);
+ __ Bind(&nan);
+ // output = 0
+ __ xorl(output, output);
+ __ Bind(&done);
+ break;
+ }
+
case Primitive::kPrimDouble:
LOG(FATAL) << "Type conversion from " << input_type
<< " to " << result_type << " not yet implemented";
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 7584f1bac1..ba4dccf598 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -30,6 +30,36 @@ void HGraph::FindBackEdges(ArenaBitVector* visited) {
VisitBlockForBackEdges(entry_block_, visited, &visiting);
}
+static void RemoveAsUser(HInstruction* instruction) {
+ for (size_t i = 0; i < instruction->InputCount(); i++) {
+ instruction->InputAt(i)->RemoveUser(instruction, i);
+ }
+
+ HEnvironment* environment = instruction->GetEnvironment();
+ if (environment != nullptr) {
+ for (size_t i = 0, e = environment->Size(); i < e; ++i) {
+ HInstruction* vreg = environment->GetInstructionAt(i);
+ if (vreg != nullptr) {
+ vreg->RemoveEnvironmentUser(environment, i);
+ }
+ }
+ }
+}
+
+void HGraph::RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visited) const {
+ for (size_t i = 0; i < blocks_.Size(); ++i) {
+ if (!visited.IsBitSet(i)) {
+ HBasicBlock* block = blocks_.Get(i);
+ for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
+ RemoveAsUser(it.Current());
+ }
+ for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
+ RemoveAsUser(it.Current());
+ }
+ }
+ }
+}
+
void HGraph::RemoveDeadBlocks(const ArenaBitVector& visited) const {
for (size_t i = 0; i < blocks_.Size(); ++i) {
if (!visited.IsBitSet(i)) {
@@ -72,16 +102,21 @@ void HGraph::BuildDominatorTree() {
// (1) Find the back edges in the graph doing a DFS traversal.
FindBackEdges(&visited);
- // (2) Remove blocks not visited during the initial DFS.
- // Step (3) requires dead blocks to be removed from the
+ // (2) Remove instructions and phis from blocks not visited during
+ // the initial DFS as users from other instructions, so that
+ // users can be safely removed before uses later.
+ RemoveInstructionsAsUsersFromDeadBlocks(visited);
+
+ // (3) Remove blocks not visited during the initial DFS.
+ // Step (4) requires dead blocks to be removed from the
// predecessors list of live blocks.
RemoveDeadBlocks(visited);
- // (3) Simplify the CFG now, so that we don't need to recompute
+ // (4) Simplify the CFG now, so that we don't need to recompute
// dominators and the reverse post order.
SimplifyCFG();
- // (4) Compute the immediate dominator of each block. We visit
+ // (5) Compute the immediate dominator of each block. We visit
// the successors of a block only when all its forward branches
// have been processed.
GrowableArray<size_t> visits(arena_, blocks_.Size());
@@ -391,19 +426,7 @@ static void Remove(HInstructionList* instruction_list,
instruction->SetBlock(nullptr);
instruction_list->RemoveInstruction(instruction);
- for (size_t i = 0; i < instruction->InputCount(); i++) {
- instruction->InputAt(i)->RemoveUser(instruction, i);
- }
-
- HEnvironment* environment = instruction->GetEnvironment();
- if (environment != nullptr) {
- for (size_t i = 0, e = environment->Size(); i < e; ++i) {
- HInstruction* vreg = environment->GetInstructionAt(i);
- if (vreg != nullptr) {
- vreg->RemoveEnvironmentUser(environment, i);
- }
- }
- }
+ RemoveAsUser(instruction);
}
void HBasicBlock::RemoveInstruction(HInstruction* instruction) {
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 4706b3beab..3908a61910 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -173,6 +173,7 @@ class HGraph : public ArenaObject<kArenaAllocMisc> {
void VisitBlockForBackEdges(HBasicBlock* block,
ArenaBitVector* visited,
ArenaBitVector* visiting);
+ void RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visited) const;
void RemoveDeadBlocks(const ArenaBitVector& visited) const;
ArenaAllocator* const arena_;
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index a1ac2f0761..d7669e1104 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -25,10 +25,6 @@
#include <string>
#include <vector>
-#ifndef __APPLE__
-#include <malloc.h> // For mallinfo
-#endif
-
#if defined(__linux__) && defined(__arm__)
#include <sys/personality.h>
#include <sys/utsname.h>
@@ -987,6 +983,12 @@ class Dex2Oat FINAL {
return true;
}
+ void EraseOatFile() {
+ DCHECK(oat_file_.get() != nullptr);
+ oat_file_->Erase();
+ oat_file_.reset();
+ }
+
// Set up the environment for compilation. Includes starting the runtime and loading/opening the
// boot class path.
bool Setup() {
@@ -1301,7 +1303,6 @@ class Dex2Oat FINAL {
if (!driver_->WriteElf(android_root_, is_host_, dex_files_, oat_writer.get(),
oat_file_.get())) {
LOG(ERROR) << "Failed to write ELF file " << oat_file_->GetPath();
- oat_file_->Erase();
return false;
}
}
@@ -1609,20 +1610,9 @@ class Dex2Oat FINAL {
}
void LogCompletionTime() {
- std::ostringstream mallinfostr;
-#ifdef HAVE_MALLOC_H
- struct mallinfo info = mallinfo();
- const size_t allocated_space = static_cast<size_t>(info.uordblks);
- const size_t free_space = static_cast<size_t>(info.fordblks);
- mallinfostr << " native alloc=" << PrettySize(allocated_space) << " free="
- << PrettySize(free_space);
-#endif
- const ArenaPool* arena_pool = driver_->GetArenaPool();
- gc::Heap* heap = Runtime::Current()->GetHeap();
LOG(INFO) << "dex2oat took " << PrettyDuration(NanoTime() - start_ns_)
- << " (threads: " << thread_count_ << ")"
- << " arena alloc=" << PrettySize(arena_pool->GetBytesAllocated())
- << " java alloc=" << PrettySize(heap->GetBytesAllocated()) << mallinfostr.str();
+ << " (threads: " << thread_count_ << ") "
+ << driver_->GetMemoryUsageString();
}
std::unique_ptr<CompilerOptions> compiler_options_;
@@ -1712,6 +1702,7 @@ static int CompileImage(Dex2Oat& dex2oat) {
// Create the boot.oat.
if (!dex2oat.CreateOatFile()) {
+ dex2oat.EraseOatFile();
return EXIT_FAILURE;
}
@@ -1756,6 +1747,7 @@ static int CompileApp(Dex2Oat& dex2oat) {
// Create the app oat.
if (!dex2oat.CreateOatFile()) {
+ dex2oat.EraseOatFile();
return EXIT_FAILURE;
}
@@ -1813,6 +1805,7 @@ static int dex2oat(int argc, char** argv) {
LOG(INFO) << CommandLine();
if (!dex2oat.Setup()) {
+ dex2oat.EraseOatFile();
return EXIT_FAILURE;
}
diff --git a/test/004-JniTest/jni_test.cc b/test/004-JniTest/jni_test.cc
index c2877be02e..544cbc503e 100644
--- a/test/004-JniTest/jni_test.cc
+++ b/test/004-JniTest/jni_test.cc
@@ -294,20 +294,20 @@ static void testShallowGetCallingClassLoader(JNIEnv* env) {
assert(!env->ExceptionCheck());
// Create a string object.
- jobject library_string = env->NewStringUTF("arttest");
+ jobject library_string = env->NewStringUTF("non_existing_library");
assert(library_string != nullptr);
assert(!env->ExceptionCheck());
env->CallStaticVoidMethod(system_clazz, loadLibraryMethodId, library_string);
- if (env->ExceptionCheck()) {
- // At most we expect UnsatisfiedLinkError.
- jthrowable thrown = env->ExceptionOccurred();
- env->ExceptionClear();
-
- jclass unsatisfied_link_error_clazz = env->FindClass("java/lang/UnsatisfiedLinkError");
- jclass thrown_class = env->GetObjectClass(thrown);
- assert(env->IsSameObject(unsatisfied_link_error_clazz, thrown_class));
- }
+ assert(env->ExceptionCheck());
+
+ // We expect UnsatisfiedLinkError.
+ jthrowable thrown = env->ExceptionOccurred();
+ env->ExceptionClear();
+
+ jclass unsatisfied_link_error_clazz = env->FindClass("java/lang/UnsatisfiedLinkError");
+ jclass thrown_class = env->GetObjectClass(thrown);
+ assert(env->IsSameObject(unsatisfied_link_error_clazz, thrown_class));
}
}
diff --git a/test/422-type-conversion/src/Main.java b/test/422-type-conversion/src/Main.java
index c434db37c9..e7dbe2463f 100644
--- a/test/422-type-conversion/src/Main.java
+++ b/test/422-type-conversion/src/Main.java
@@ -91,6 +91,9 @@ public class Main {
// Generate, compile and check long-to-double Dex instructions.
longToDouble();
+ // Generate, compile and check float-to-int Dex instructions.
+ floatToInt();
+
// Generate, compile and check int-to-byte Dex instructions.
shortToByte();
intToByte();
@@ -313,6 +316,32 @@ public class Main {
assertDoubleEquals(-9223372036854775808D, $opt$LongToDouble(-9223372036854775808L)); // -(2^63)
}
+ private static void floatToInt() {
+ assertIntEquals(1, $opt$FloatToInt(1F));
+ assertIntEquals(0, $opt$FloatToInt(0F));
+ assertIntEquals(0, $opt$FloatToInt(-0F));
+ assertIntEquals(-1, $opt$FloatToInt(-1F));
+ assertIntEquals(51, $opt$FloatToInt(51F));
+ assertIntEquals(-51, $opt$FloatToInt(-51F));
+ assertIntEquals(0, $opt$FloatToInt(0.5F));
+ assertIntEquals(0, $opt$FloatToInt(0.4999999F));
+ assertIntEquals(0, $opt$FloatToInt(-0.4999999F));
+ assertIntEquals(0, $opt$FloatToInt(-0.5F));
+ assertIntEquals(42, $opt$FloatToInt(42.199F));
+ assertIntEquals(-42, $opt$FloatToInt(-42.199F));
+ assertIntEquals(2147483647, $opt$FloatToInt(2147483647F)); // 2^31 - 1
+ assertIntEquals(-2147483648, $opt$FloatToInt(-2147483647F)); // -(2^31 - 1)
+ assertIntEquals(-2147483648, $opt$FloatToInt(-2147483648F)); // -(2^31)
+ assertIntEquals(2147483647, $opt$FloatToInt(2147483648F)); // (2^31)
+ assertIntEquals(-2147483648, $opt$FloatToInt(-2147483649F)); // -(2^31 + 1)
+ assertIntEquals(2147483647, $opt$FloatToInt(9223372036854775807F)); // 2^63 - 1
+ assertIntEquals(-2147483648, $opt$FloatToInt(-9223372036854775807F)); // -(2^63 - 1)
+ assertIntEquals(-2147483648, $opt$FloatToInt(-9223372036854775808F)); // -(2^63)
+ assertIntEquals(0, $opt$FloatToInt(Float.NaN));
+ assertIntEquals(2147483647, $opt$FloatToInt(Float.POSITIVE_INFINITY));
+ assertIntEquals(-2147483648, $opt$FloatToInt(Float.NEGATIVE_INFINITY));
+ }
+
private static void shortToByte() {
assertByteEquals((byte)1, $opt$ShortToByte((short)1));
assertByteEquals((byte)0, $opt$ShortToByte((short)0));
@@ -468,6 +497,9 @@ public class Main {
// This method produces a long-to-double Dex instruction.
static double $opt$LongToDouble(long a){ return (double)a; }
+ // This method produces a float-to-int Dex instruction.
+ static int $opt$FloatToInt(float a){ return (int)a; }
+
// These methods produce int-to-byte Dex instructions.
static byte $opt$ShortToByte(short a){ return (byte)a; }
static byte $opt$IntToByte(int a){ return (byte)a; }
diff --git a/test/435-try-finally-without-catch/expected.txt b/test/435-try-finally-without-catch/expected.txt
new file mode 100644
index 0000000000..8a67802d72
--- /dev/null
+++ b/test/435-try-finally-without-catch/expected.txt
@@ -0,0 +1,3 @@
+In finally
+In finally
+In finally
diff --git a/test/435-try-finally-without-catch/info.txt b/test/435-try-finally-without-catch/info.txt
new file mode 100644
index 0000000000..46217c516b
--- /dev/null
+++ b/test/435-try-finally-without-catch/info.txt
@@ -0,0 +1,26 @@
+Exercise a method containing a `try' statement with several
+instructions with a `finally' clause but without any `catch' block,
+enclosed in a loop.
+
+When dx processes an integer division (or modulo) enclosing a `try'
+block and whose result is assigned to a local value, it is smart
+enough not to emit a `div-int' (or `rem-int') instruction when the
+divisor is non-null, as it wouldn't be used. However, dx is not
+that clever regarding exception handling: if the divisor is known to
+be non-null at compile-time (as is the case in this test), it will
+still emit a block with the exception catching and rethrowing
+mechanism, even if it is not used.
+
+This used to be a problem for a `try' block followed by a `finally'
+clause but with no `catch' block: in that case, the generated Dex code
+item would list zero catch block for this method (see
+art::CodeItem::tries_size_) and the optimizing compiler would have no
+clue that it contains a `try' statement, which it cannot optimize
+(yet). With no hint that this method might contain one (or several)
+special block(s) related to `catch'-less `try' statement(s), the
+optimizing compiler considered this (these) as dead block(s) and
+improperly tried to remove its (their) instructions, sometimes
+removing instructions used by others instructions, thus triggering
+assertions. The optimizing compiler was thus adjusted to remove these
+instructions in a proper fashion, by removing them as users first, and
+then by suppressing them for good.
diff --git a/test/435-try-finally-without-catch/src/Main.java b/test/435-try-finally-without-catch/src/Main.java
new file mode 100644
index 0000000000..3c29ce8476
--- /dev/null
+++ b/test/435-try-finally-without-catch/src/Main.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+
+ public static void main(String[] args){
+ foo();
+ }
+
+ // Reduced test case inspired by constantPropagationTest() from
+ // test/083-compiler-regressions.
+ static void foo() {
+ int a = 0;
+ int b = 1;
+
+ for (int i = 0; i < 3; i++) {
+ try {
+ a = 1;
+ // Would throw an ArithmeticException if b were null (hence
+ // the enclosing `try' statement).
+ int c = a % b;
+ }
+ finally {
+ System.out.println("In finally");
+ }
+ }
+ }
+}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 3c959fbcb3..b85685ba76 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -472,6 +472,7 @@ define define-test-art-run-test
else
ifeq ($(4),default)
test_groups += ART_RUN_TEST_$$(uc_host_or_target)_DEFAULT_RULES
+ run_test_options += --quick
else
$$(error found $(4) expected $(COMPILER_TYPES))
endif
diff --git a/test/run-test b/test/run-test
index 6b8f00748b..2abc1fa262 100755
--- a/test/run-test
+++ b/test/run-test
@@ -194,6 +194,9 @@ while true; do
run_args="${run_args} -Xcompiler-option --compiler-backend=Optimizing"
image_suffix="-optimizing"
shift
+ elif [ "x$1" = "x--quick" ]; then
+ run_args="${run_args} -Xcompiler-option --compiler-backend=Quick"
+ shift
elif [ "x$1" = "x--no-verify" ]; then
run_args="${run_args} --no-verify"
shift
@@ -421,6 +424,7 @@ if [ "$usage" = "yes" ]; then
echo " --build-only Build test files only (off by default)."
echo " --interpreter Enable interpreter only mode (off by default)."
echo " --optimizing Enable optimizing compiler (off by default)."
+ echo " --quick Use Quick compiler (default)."
echo " --no-verify Turn off verification (on by default)."
echo " --no-optimize Turn off optimization (on by default)."
echo " --no-precise Turn off precise GC (on by default)."