Runtime implementation of try catch inlining
The main differences in the runtime are:
1) We now use a list of dex_pcs to find the correct catch handler
instead of a single dex pc
2) We now need to restore vregs of the whole frame, which may be
an inline frame.
Bug: 227283224
Test: art/test/testrunner/testrunner.py --host --64 --optimizing -b
Change-Id: I95d2f32088e1d420c83962a1693be18f3b63f8b4
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index 430aaa3..514d30e 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -20,9 +20,12 @@
#include <limits>
#include "arch/instruction_set.h"
+#include "base/array_ref.h"
#include "base/bit_memory_region.h"
#include "base/bit_table.h"
#include "base/bit_utils.h"
+#include "base/globals.h"
+#include "base/logging.h"
#include "base/memory_region.h"
#include "dex/dex_file_types.h"
#include "dex_register_location.h"
@@ -360,15 +363,12 @@
return GetMethodInfoOf(inline_info).GetMethodIndex();
}
+ // Returns the dex registers for `stack_map`, ignoring any inlined dex registers.
ALWAYS_INLINE DexRegisterMap GetDexRegisterMapOf(StackMap stack_map) const {
- if (stack_map.HasDexRegisterMap()) {
- DexRegisterMap map(number_of_dex_registers_, DexRegisterLocation::Invalid());
- DecodeDexRegisterMap(stack_map.Row(), /* first_dex_register= */ 0, &map);
- return map;
- }
- return DexRegisterMap(0, DexRegisterLocation::None());
+ return GetDexRegisterMapOf(stack_map, /* first= */ 0, number_of_dex_registers_);
}
+ // Returns the dex register map of `inline_info`, and just those registers.
ALWAYS_INLINE DexRegisterMap GetInlineDexRegisterMapOf(StackMap stack_map,
InlineInfo inline_info) const {
if (stack_map.HasDexRegisterMap()) {
@@ -381,6 +381,17 @@
? number_of_dex_registers_
: inline_infos_.GetRow(inline_info.Row() - 1).GetNumberOfDexRegisters();
uint32_t last = inline_info.GetNumberOfDexRegisters();
+ return GetDexRegisterMapOf(stack_map, first, last);
+ }
+ return DexRegisterMap(0, DexRegisterLocation::None());
+ }
+
+ // Returns the dex register map of `stack_map` in the range the range [first, last).
+ ALWAYS_INLINE DexRegisterMap GetDexRegisterMapOf(StackMap stack_map,
+ uint32_t first,
+ uint32_t last) const {
+ if (stack_map.HasDexRegisterMap()) {
+ DCHECK_LE(first, last);
DexRegisterMap map(last - first, DexRegisterLocation::Invalid());
DecodeDexRegisterMap(stack_map.Row(), first, &map);
return map;
@@ -409,12 +420,39 @@
return stack_maps_.GetInvalidRow();
}
- // Searches the stack map list backwards because catch stack maps are stored at the end.
- StackMap GetCatchStackMapForDexPc(uint32_t dex_pc) const {
+ StackMap GetCatchStackMapForDexPc(ArrayRef<const uint32_t> dex_pcs) const {
+ // Searches the stack map list backwards because catch stack maps are stored at the end.
for (size_t i = GetNumberOfStackMaps(); i > 0; --i) {
StackMap stack_map = GetStackMapAt(i - 1);
- if (stack_map.GetDexPc() == dex_pc && stack_map.GetKind() == StackMap::Kind::Catch) {
- return stack_map;
+ if (UNLIKELY(stack_map.GetKind() != StackMap::Kind::Catch)) {
+ // Early break since we should have catch stack maps only at the end.
+ if (kIsDebugBuild) {
+ for (size_t j = i - 1; j > 0; --j) {
+ DCHECK(GetStackMapAt(j - 1).GetKind() != StackMap::Kind::Catch);
+ }
+ }
+ break;
+ }
+
+ // Both the handler dex_pc and all of the inline dex_pcs have to match i.e. we want dex_pcs to
+ // be [stack_map_dex_pc, inline_dex_pc_1, ..., inline_dex_pc_n].
+ if (stack_map.GetDexPc() != dex_pcs.front()) {
+ continue;
+ }
+
+ const BitTableRange<InlineInfo>& inline_infos = GetInlineInfosOf(stack_map);
+ if (inline_infos.size() == dex_pcs.size() - 1) {
+ bool matching_dex_pcs = true;
+ for (size_t inline_info_index = 0; inline_info_index < inline_infos.size();
+ ++inline_info_index) {
+ if (inline_infos[inline_info_index].GetDexPc() != dex_pcs[inline_info_index + 1]) {
+ matching_dex_pcs = false;
+ break;
+ }
+ }
+ if (matching_dex_pcs) {
+ return stack_map;
+ }
}
}
return stack_maps_.GetInvalidRow();
@@ -453,6 +491,10 @@
return (*code_info_data & kIsDebuggable) != 0;
}
+ uint32_t GetNumberOfDexRegisters() {
+ return number_of_dex_registers_;
+ }
+
private:
// Scan backward to determine dex register locations at given stack map.
void DecodeDexRegisterMap(uint32_t stack_map_index,