ART: Introduce stackmap with no DexRegInfo.
Some of safepoints don't need to have DexRegisterMap info;
this will decrease the stackmap size.
.oat file size reduction:
- boot.oat: -233 kb (-5.4%)
- boot-framework.oat: -704 kb (-4.9%)
Test: 461-get-reference-vreg, 466-get-live-vreg.
Test: 543-env-long-ref, 616-cha*.
Test: test-art-target, +gc-stress.
Change-Id: Idbad355770e30a30dcf14127642e03ee666878b8
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 3b5699b..6d3a5c6 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -1088,6 +1088,30 @@
return stack_map;
}
+// Returns whether stackmap dex register info is needed for the instruction.
+//
+// The following cases mandate having a dex register map:
+// * Deoptimization
+// when we need to obtain the values to restore actual vregisters for interpreter.
+// * Debuggability
+// when we want to observe the values / asynchronously deoptimize.
+// * Monitor operations
+// to allow dumping in a stack trace locked dex registers for non-debuggable code.
+// * On-stack-replacement (OSR)
+// when entering compiled for OSR code from the interpreter we need to initialize the compiled
+// code values with the values from the vregisters.
+// * Method local catch blocks
+// a catch block must see the environment of the instruction from the same method that can
+// throw to this block.
+static bool NeedsVregInfo(HInstruction* instruction, bool osr) {
+ HGraph* graph = instruction->GetBlock()->GetGraph();
+ return instruction->IsDeoptimize() ||
+ graph->IsDebuggable() ||
+ graph->HasMonitorOperations() ||
+ osr ||
+ instruction->CanThrowIntoCatchBlock();
+}
+
void CodeGenerator::RecordPcInfo(HInstruction* instruction,
uint32_t dex_pc,
SlowPathCode* slow_path,
@@ -1166,12 +1190,15 @@
StackMap::Kind kind = native_debug_info
? StackMap::Kind::Debug
: (osr ? StackMap::Kind::OSR : StackMap::Kind::Default);
+ bool needs_vreg_info = NeedsVregInfo(instruction, osr);
stack_map_stream->BeginStackMapEntry(outer_dex_pc,
native_pc,
register_mask,
locations->GetStackMask(),
- kind);
- EmitEnvironment(environment, slow_path);
+ kind,
+ needs_vreg_info);
+
+ EmitEnvironment(environment, slow_path, needs_vreg_info);
stack_map_stream->EndStackMapEntry();
if (osr) {
@@ -1284,19 +1311,8 @@
code_generation_data_->AddSlowPath(slow_path);
}
-void CodeGenerator::EmitEnvironment(HEnvironment* environment, SlowPathCode* slow_path) {
- if (environment == nullptr) return;
-
+void CodeGenerator::EmitVRegInfo(HEnvironment* environment, SlowPathCode* slow_path) {
StackMapStream* stack_map_stream = GetStackMapStream();
- if (environment->GetParent() != nullptr) {
- // We emit the parent environment first.
- EmitEnvironment(environment->GetParent(), slow_path);
- stack_map_stream->BeginInlineInfoEntry(environment->GetMethod(),
- environment->GetDexPc(),
- environment->Size(),
- &graph_->GetDexFile());
- }
-
// Walk over the environment, and record the location of dex registers.
for (size_t i = 0, environment_size = environment->Size(); i < environment_size; ++i) {
HInstruction* current = environment->GetInstructionAt(i);
@@ -1441,8 +1457,31 @@
LOG(FATAL) << "Unexpected kind " << location.GetKind();
}
}
+}
- if (environment->GetParent() != nullptr) {
+void CodeGenerator::EmitEnvironment(HEnvironment* environment,
+ SlowPathCode* slow_path,
+ bool needs_vreg_info) {
+ if (environment == nullptr) return;
+
+ StackMapStream* stack_map_stream = GetStackMapStream();
+ bool emit_inline_info = environment->GetParent() != nullptr;
+
+ if (emit_inline_info) {
+ // We emit the parent environment first.
+ EmitEnvironment(environment->GetParent(), slow_path, needs_vreg_info);
+ stack_map_stream->BeginInlineInfoEntry(environment->GetMethod(),
+ environment->GetDexPc(),
+ needs_vreg_info ? environment->Size() : 0,
+ &graph_->GetDexFile());
+ }
+
+ if (needs_vreg_info) {
+ // If a dex register map is not required we just won't emit it.
+ EmitVRegInfo(environment, slow_path);
+ }
+
+ if (emit_inline_info) {
stack_map_stream->EndInlineInfoEntry();
}
}
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 357c4bb..d932c6a 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -761,7 +761,10 @@
size_t GetStackOffsetOfSavedRegister(size_t index);
void GenerateSlowPaths();
void BlockIfInRegister(Location location, bool is_out = false) const;
- void EmitEnvironment(HEnvironment* environment, SlowPathCode* slow_path);
+ void EmitEnvironment(HEnvironment* environment,
+ SlowPathCode* slow_path,
+ bool needs_vreg_info = true);
+ void EmitVRegInfo(HEnvironment* environment, SlowPathCode* slow_path);
OptimizingCompilerStats* stats_;
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index f8f813e..e7f0872 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -3096,6 +3096,7 @@
LoadLocal(instruction.VRegA_11x(), DataType::Type::kReference),
HMonitorOperation::OperationKind::kEnter,
dex_pc));
+ graph_->SetHasMonitorOperations(true);
break;
}
@@ -3104,6 +3105,7 @@
LoadLocal(instruction.VRegA_11x(), DataType::Type::kReference),
HMonitorOperation::OperationKind::kExit,
dex_pc));
+ graph_->SetHasMonitorOperations(true);
break;
}
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 5111036..3e6e211 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -335,6 +335,7 @@
temporaries_vreg_slots_(0),
has_bounds_checks_(false),
has_try_catch_(false),
+ has_monitor_operations_(false),
has_simd_(false),
has_loops_(false),
has_irreducible_loops_(false),
@@ -606,6 +607,9 @@
bool HasTryCatch() const { return has_try_catch_; }
void SetHasTryCatch(bool value) { has_try_catch_ = value; }
+ bool HasMonitorOperations() const { return has_monitor_operations_; }
+ void SetHasMonitorOperations(bool value) { has_monitor_operations_ = value; }
+
bool HasSIMD() const { return has_simd_; }
void SetHasSIMD(bool value) { has_simd_ = value; }
@@ -702,6 +706,10 @@
// false positives.
bool has_try_catch_;
+ // Flag whether there are any HMonitorOperation in the graph. If yes this will mandate
+ // DexRegisterMap to be present to allow deadlock analysis for non-debuggable code.
+ bool has_monitor_operations_;
+
// Flag whether SIMD instructions appear in the graph. If true, the
// code generators may have to be more careful spilling the wider
// contents of SIMD registers.
diff --git a/compiler/optimizing/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc
index afb6071c..3f6010d 100644
--- a/compiler/optimizing/stack_map_stream.cc
+++ b/compiler/optimizing/stack_map_stream.cc
@@ -81,7 +81,8 @@
uint32_t native_pc_offset,
uint32_t register_mask,
BitVector* stack_mask,
- StackMap::Kind kind) {
+ StackMap::Kind kind,
+ bool needs_vreg_info) {
DCHECK(in_method_) << "Call BeginMethod first";
DCHECK(!in_stack_map_) << "Mismatched Begin/End calls";
in_stack_map_ = true;
@@ -114,7 +115,7 @@
lazy_stack_masks_.push_back(stack_mask);
current_inline_infos_.clear();
current_dex_registers_.clear();
- expected_num_dex_registers_ = num_dex_registers_;
+ expected_num_dex_registers_ = needs_vreg_info ? num_dex_registers_ : 0u;
if (kVerifyStackMaps) {
size_t stack_map_index = stack_maps_.size();
diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h
index 33c624a..f45e3d7 100644
--- a/compiler/optimizing/stack_map_stream.h
+++ b/compiler/optimizing/stack_map_stream.h
@@ -68,7 +68,8 @@
uint32_t native_pc_offset,
uint32_t register_mask = 0,
BitVector* sp_mask = nullptr,
- StackMap::Kind kind = StackMap::Kind::Default);
+ StackMap::Kind kind = StackMap::Kind::Default,
+ bool needs_vreg_info = true);
void EndStackMapEntry();
void AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value) {