blob: a2c30e7681f1c33ebd5d82ad998350659053f2a3 [file] [log] [blame]
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "stack_map.h"
Mathieu Chartiere5d80f82015-10-15 17:47:48 -070018
Nicolas Geoffray5d37c152017-01-12 13:25:19 +000019#include "art_method.h"
Mathieu Chartiere5d80f82015-10-15 17:47:48 -070020#include "base/arena_bit_vector.h"
Vladimír Marko434d9682022-11-04 14:04:17 +000021#include "base/macros.h"
David Sehr3215fff2018-04-03 17:10:12 -070022#include "base/malloc_arena_pool.h"
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010023#include "stack_map_stream.h"
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010024
25#include "gtest/gtest.h"
26
Vladimír Marko434d9682022-11-04 14:04:17 +000027namespace art HIDDEN {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010028
David Srbecky09ed0982016-02-12 21:58:43 +000029// Check that the stack mask of given stack map is identical
30// to the given bit vector. Returns true if they are same.
31static bool CheckStackMask(
David Srbecky45aa5982016-03-18 02:15:09 +000032 const CodeInfo& code_info,
David Srbecky09ed0982016-02-12 21:58:43 +000033 const StackMap& stack_map,
David Srbecky09ed0982016-02-12 21:58:43 +000034 const BitVector& bit_vector) {
David Srbecky052f8ca2018-04-26 15:42:54 +010035 BitMemoryRegion stack_mask = code_info.GetStackMaskOf(stack_map);
David Srbecky4b59d102018-05-29 21:46:10 +000036 if (bit_vector.GetNumberOfBits() > stack_mask.size_in_bits()) {
David Srbecky09ed0982016-02-12 21:58:43 +000037 return false;
38 }
David Srbecky4b59d102018-05-29 21:46:10 +000039 for (size_t i = 0; i < stack_mask.size_in_bits(); ++i) {
David Srbecky45aa5982016-03-18 02:15:09 +000040 if (stack_mask.LoadBit(i) != bit_vector.IsBitSet(i)) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010041 return false;
42 }
43 }
44 return true;
45}
46
Roland Levillaina552e1c2015-03-26 15:01:03 +000047using Kind = DexRegisterLocation::Kind;
48
David Srbeckyd775f962018-05-30 18:12:52 +010049constexpr static uint32_t kPcAlign = GetInstructionSetInstructionAlignment(kRuntimeISA);
50
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010051TEST(StackMapTest, Test1) {
David Sehr3215fff2018-04-03 17:10:12 -070052 MallocArenaPool pool;
Vladimir Marko174b2e22017-10-12 13:34:49 +010053 ArenaStack arena_stack(&pool);
54 ScopedArenaAllocator allocator(&arena_stack);
Vladimir Marko69d310e2017-10-09 14:12:23 +010055 StackMapStream stream(&allocator, kRuntimeISA);
Mythri Alled9e83772022-07-14 09:38:49 +000056 stream.BeginMethod(/* frame_size_in_bytes= */ 32,
57 /* core_spill_mask= */ 0,
58 /* fp_spill_mask= */ 0,
59 /* num_dex_registers= */ 2,
60 /* baseline= */ false,
61 /* debuggable= */ false);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010062
Vladimir Marko69d310e2017-10-09 14:12:23 +010063 ArenaBitVector sp_mask(&allocator, 0, false);
Roland Levillain12baf472015-03-05 12:41:42 +000064 size_t number_of_dex_registers = 2;
David Srbeckyf6ba5b32018-06-23 22:05:49 +010065 stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +010066 stream.AddDexRegisterEntry(Kind::kInStack, 0); // Short location.
67 stream.AddDexRegisterEntry(Kind::kConstant, -2); // Short location.
Calin Juravle4f46ac52015-04-23 18:47:21 +010068 stream.EndStackMapEntry();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010069
David Srbecky17b4d2b2021-03-02 18:14:31 +000070 stream.EndMethod(64 * kPcAlign);
David Srbeckye7a91942018-08-01 17:23:53 +010071 ScopedArenaVector<uint8_t> memory = stream.Encode();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010072
David Srbeckye7a91942018-08-01 17:23:53 +010073 CodeInfo code_info(memory.data());
David Srbecky052f8ca2018-04-26 15:42:54 +010074 ASSERT_EQ(1u, code_info.GetNumberOfStackMaps());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010075
David Srbecky052f8ca2018-04-26 15:42:54 +010076 uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries();
David Srbecky09ed0982016-02-12 21:58:43 +000077 ASSERT_EQ(2u, number_of_catalog_entries);
Roland Levillaina552e1c2015-03-26 15:01:03 +000078
David Srbecky052f8ca2018-04-26 15:42:54 +010079 StackMap stack_map = code_info.GetStackMapAt(0);
80 ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0)));
David Srbeckyd775f962018-05-30 18:12:52 +010081 ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64 * kPcAlign)));
David Srbecky052f8ca2018-04-26 15:42:54 +010082 ASSERT_EQ(0u, stack_map.GetDexPc());
David Srbeckyd775f962018-05-30 18:12:52 +010083 ASSERT_EQ(64u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA));
David Srbecky052f8ca2018-04-26 15:42:54 +010084 ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(stack_map));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010085
David Srbecky052f8ca2018-04-26 15:42:54 +010086 ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010087
David Srbecky052f8ca2018-04-26 15:42:54 +010088 ASSERT_TRUE(stack_map.HasDexRegisterMap());
David Srbeckyfd89b072018-06-03 12:00:22 +010089 DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map);
90 ASSERT_EQ(number_of_dex_registers, dex_register_map.size());
David Srbeckye1402122018-06-13 18:20:45 +010091 ASSERT_TRUE(dex_register_map[0].IsLive());
92 ASSERT_TRUE(dex_register_map[1].IsLive());
David Srbecky71ec1cc2018-05-18 15:57:25 +010093 ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters());
Roland Levillaina552e1c2015-03-26 15:01:03 +000094
David Srbeckye1402122018-06-13 18:20:45 +010095 ASSERT_EQ(Kind::kInStack, dex_register_map[0].GetKind());
96 ASSERT_EQ(Kind::kConstant, dex_register_map[1].GetKind());
97 ASSERT_EQ(0, dex_register_map[0].GetStackOffsetInBytes());
98 ASSERT_EQ(-2, dex_register_map[1].GetConstant());
Roland Levillaina552e1c2015-03-26 15:01:03 +000099
David Srbecky71ec1cc2018-05-18 15:57:25 +0100100 DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(0);
101 DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(1);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000102 ASSERT_EQ(Kind::kInStack, location0.GetKind());
103 ASSERT_EQ(Kind::kConstant, location1.GetKind());
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000104 ASSERT_EQ(0, location0.GetValue());
105 ASSERT_EQ(-2, location1.GetValue());
Roland Levillain12baf472015-03-05 12:41:42 +0000106
David Srbecky052f8ca2018-04-26 15:42:54 +0100107 ASSERT_FALSE(stack_map.HasInlineInfo());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100108}
109
110TEST(StackMapTest, Test2) {
David Sehr3215fff2018-04-03 17:10:12 -0700111 MallocArenaPool pool;
Vladimir Marko174b2e22017-10-12 13:34:49 +0100112 ArenaStack arena_stack(&pool);
113 ScopedArenaAllocator allocator(&arena_stack);
Vladimir Marko69d310e2017-10-09 14:12:23 +0100114 StackMapStream stream(&allocator, kRuntimeISA);
Mythri Alled9e83772022-07-14 09:38:49 +0000115 stream.BeginMethod(/* frame_size_in_bytes= */ 32,
116 /* core_spill_mask= */ 0,
117 /* fp_spill_mask= */ 0,
118 /* num_dex_registers= */ 2,
119 /* baseline= */ false,
120 /* debuggable= */ false);
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000121 ArtMethod art_method;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100122
Vladimir Marko69d310e2017-10-09 14:12:23 +0100123 ArenaBitVector sp_mask1(&allocator, 0, true);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100124 sp_mask1.SetBit(2);
125 sp_mask1.SetBit(4);
Roland Levillain12baf472015-03-05 12:41:42 +0000126 size_t number_of_dex_registers = 2;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100127 size_t number_of_dex_registers_in_inline_info = 0;
David Srbeckyf6ba5b32018-06-23 22:05:49 +0100128 stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask1);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100129 stream.AddDexRegisterEntry(Kind::kInStack, 0); // Short location.
130 stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location.
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000131 stream.BeginInlineInfoEntry(&art_method, 3, number_of_dex_registers_in_inline_info);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100132 stream.EndInlineInfoEntry();
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000133 stream.BeginInlineInfoEntry(&art_method, 2, number_of_dex_registers_in_inline_info);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100134 stream.EndInlineInfoEntry();
Calin Juravle4f46ac52015-04-23 18:47:21 +0100135 stream.EndStackMapEntry();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100136
Vladimir Marko69d310e2017-10-09 14:12:23 +0100137 ArenaBitVector sp_mask2(&allocator, 0, true);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100138 sp_mask2.SetBit(3);
David Brazdilf10a25f2015-06-02 14:29:52 +0100139 sp_mask2.SetBit(8);
David Srbeckyf6ba5b32018-06-23 22:05:49 +0100140 stream.BeginStackMapEntry(1, 128 * kPcAlign, 0xFF, &sp_mask2);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100141 stream.AddDexRegisterEntry(Kind::kInRegister, 18); // Short location.
142 stream.AddDexRegisterEntry(Kind::kInFpuRegister, 3); // Short location.
Calin Juravle4f46ac52015-04-23 18:47:21 +0100143 stream.EndStackMapEntry();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100144
Vladimir Marko69d310e2017-10-09 14:12:23 +0100145 ArenaBitVector sp_mask3(&allocator, 0, true);
David Brazdild9cb68e2015-08-25 13:52:43 +0100146 sp_mask3.SetBit(1);
147 sp_mask3.SetBit(5);
David Srbeckyf6ba5b32018-06-23 22:05:49 +0100148 stream.BeginStackMapEntry(2, 192 * kPcAlign, 0xAB, &sp_mask3);
David Brazdild9cb68e2015-08-25 13:52:43 +0100149 stream.AddDexRegisterEntry(Kind::kInRegister, 6); // Short location.
150 stream.AddDexRegisterEntry(Kind::kInRegisterHigh, 8); // Short location.
151 stream.EndStackMapEntry();
152
Vladimir Marko69d310e2017-10-09 14:12:23 +0100153 ArenaBitVector sp_mask4(&allocator, 0, true);
David Brazdild9cb68e2015-08-25 13:52:43 +0100154 sp_mask4.SetBit(6);
155 sp_mask4.SetBit(7);
David Srbeckyf6ba5b32018-06-23 22:05:49 +0100156 stream.BeginStackMapEntry(3, 256 * kPcAlign, 0xCD, &sp_mask4);
David Brazdild9cb68e2015-08-25 13:52:43 +0100157 stream.AddDexRegisterEntry(Kind::kInFpuRegister, 3); // Short location, same in stack map 2.
158 stream.AddDexRegisterEntry(Kind::kInFpuRegisterHigh, 1); // Short location.
159 stream.EndStackMapEntry();
160
David Srbecky17b4d2b2021-03-02 18:14:31 +0000161 stream.EndMethod(256 * kPcAlign);
David Srbeckye7a91942018-08-01 17:23:53 +0100162 ScopedArenaVector<uint8_t> memory = stream.Encode();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100163
David Srbeckye7a91942018-08-01 17:23:53 +0100164 CodeInfo code_info(memory.data());
David Srbecky052f8ca2018-04-26 15:42:54 +0100165 ASSERT_EQ(4u, code_info.GetNumberOfStackMaps());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100166
David Srbecky052f8ca2018-04-26 15:42:54 +0100167 uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries();
David Srbecky09ed0982016-02-12 21:58:43 +0000168 ASSERT_EQ(7u, number_of_catalog_entries);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000169
Roland Levillain12baf472015-03-05 12:41:42 +0000170 // First stack map.
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000171 {
David Srbecky052f8ca2018-04-26 15:42:54 +0100172 StackMap stack_map = code_info.GetStackMapAt(0);
173 ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0)));
David Srbeckyd775f962018-05-30 18:12:52 +0100174 ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64 * kPcAlign)));
David Srbecky052f8ca2018-04-26 15:42:54 +0100175 ASSERT_EQ(0u, stack_map.GetDexPc());
David Srbeckyd775f962018-05-30 18:12:52 +0100176 ASSERT_EQ(64u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA));
David Srbecky052f8ca2018-04-26 15:42:54 +0100177 ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(stack_map));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100178
David Srbecky052f8ca2018-04-26 15:42:54 +0100179 ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask1));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100180
David Srbecky052f8ca2018-04-26 15:42:54 +0100181 ASSERT_TRUE(stack_map.HasDexRegisterMap());
David Srbeckyfd89b072018-06-03 12:00:22 +0100182 DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map);
183 ASSERT_EQ(number_of_dex_registers, dex_register_map.size());
David Srbeckye1402122018-06-13 18:20:45 +0100184 ASSERT_TRUE(dex_register_map[0].IsLive());
185 ASSERT_TRUE(dex_register_map[1].IsLive());
David Srbecky71ec1cc2018-05-18 15:57:25 +0100186 ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters());
Roland Levillaina552e1c2015-03-26 15:01:03 +0000187
David Srbeckye1402122018-06-13 18:20:45 +0100188 ASSERT_EQ(Kind::kInStack, dex_register_map[0].GetKind());
189 ASSERT_EQ(Kind::kConstant, dex_register_map[1].GetKind());
190 ASSERT_EQ(0, dex_register_map[0].GetStackOffsetInBytes());
191 ASSERT_EQ(-2, dex_register_map[1].GetConstant());
Roland Levillaina552e1c2015-03-26 15:01:03 +0000192
David Srbecky71ec1cc2018-05-18 15:57:25 +0100193 DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(0);
194 DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(1);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000195 ASSERT_EQ(Kind::kInStack, location0.GetKind());
196 ASSERT_EQ(Kind::kConstant, location1.GetKind());
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000197 ASSERT_EQ(0, location0.GetValue());
198 ASSERT_EQ(-2, location1.GetValue());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100199
David Srbecky052f8ca2018-04-26 15:42:54 +0100200 ASSERT_TRUE(stack_map.HasInlineInfo());
David Srbecky93bd3612018-07-02 19:30:18 +0100201 auto inline_infos = code_info.GetInlineInfosOf(stack_map);
202 ASSERT_EQ(2u, inline_infos.size());
203 ASSERT_EQ(3u, inline_infos[0].GetDexPc());
204 ASSERT_EQ(2u, inline_infos[1].GetDexPc());
205 ASSERT_TRUE(inline_infos[0].EncodesArtMethod());
206 ASSERT_TRUE(inline_infos[1].EncodesArtMethod());
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000207 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100208
Roland Levillain12baf472015-03-05 12:41:42 +0000209 // Second stack map.
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000210 {
David Srbecky052f8ca2018-04-26 15:42:54 +0100211 StackMap stack_map = code_info.GetStackMapAt(1);
212 ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(1u)));
David Srbeckyd775f962018-05-30 18:12:52 +0100213 ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(128u * kPcAlign)));
David Srbecky052f8ca2018-04-26 15:42:54 +0100214 ASSERT_EQ(1u, stack_map.GetDexPc());
David Srbeckyd775f962018-05-30 18:12:52 +0100215 ASSERT_EQ(128u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA));
David Srbecky052f8ca2018-04-26 15:42:54 +0100216 ASSERT_EQ(0xFFu, code_info.GetRegisterMaskOf(stack_map));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100217
David Srbecky052f8ca2018-04-26 15:42:54 +0100218 ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask2));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100219
David Srbecky052f8ca2018-04-26 15:42:54 +0100220 ASSERT_TRUE(stack_map.HasDexRegisterMap());
David Srbeckyfd89b072018-06-03 12:00:22 +0100221 DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map);
222 ASSERT_EQ(number_of_dex_registers, dex_register_map.size());
David Srbeckye1402122018-06-13 18:20:45 +0100223 ASSERT_TRUE(dex_register_map[0].IsLive());
224 ASSERT_TRUE(dex_register_map[1].IsLive());
David Srbecky71ec1cc2018-05-18 15:57:25 +0100225 ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters());
Roland Levillaina552e1c2015-03-26 15:01:03 +0000226
David Srbeckye1402122018-06-13 18:20:45 +0100227 ASSERT_EQ(Kind::kInRegister, dex_register_map[0].GetKind());
228 ASSERT_EQ(Kind::kInFpuRegister, dex_register_map[1].GetKind());
229 ASSERT_EQ(18, dex_register_map[0].GetMachineRegister());
230 ASSERT_EQ(3, dex_register_map[1].GetMachineRegister());
Roland Levillaina552e1c2015-03-26 15:01:03 +0000231
David Srbecky71ec1cc2018-05-18 15:57:25 +0100232 DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(2);
233 DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(3);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000234 ASSERT_EQ(Kind::kInRegister, location0.GetKind());
235 ASSERT_EQ(Kind::kInFpuRegister, location1.GetKind());
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000236 ASSERT_EQ(18, location0.GetValue());
237 ASSERT_EQ(3, location1.GetValue());
Roland Levillain12baf472015-03-05 12:41:42 +0000238
David Srbecky052f8ca2018-04-26 15:42:54 +0100239 ASSERT_FALSE(stack_map.HasInlineInfo());
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000240 }
David Brazdild9cb68e2015-08-25 13:52:43 +0100241
242 // Third stack map.
243 {
David Srbecky052f8ca2018-04-26 15:42:54 +0100244 StackMap stack_map = code_info.GetStackMapAt(2);
245 ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(2u)));
David Srbeckyd775f962018-05-30 18:12:52 +0100246 ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(192u * kPcAlign)));
David Srbecky052f8ca2018-04-26 15:42:54 +0100247 ASSERT_EQ(2u, stack_map.GetDexPc());
David Srbeckyd775f962018-05-30 18:12:52 +0100248 ASSERT_EQ(192u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA));
David Srbecky052f8ca2018-04-26 15:42:54 +0100249 ASSERT_EQ(0xABu, code_info.GetRegisterMaskOf(stack_map));
David Brazdild9cb68e2015-08-25 13:52:43 +0100250
David Srbecky052f8ca2018-04-26 15:42:54 +0100251 ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask3));
David Brazdild9cb68e2015-08-25 13:52:43 +0100252
David Srbecky052f8ca2018-04-26 15:42:54 +0100253 ASSERT_TRUE(stack_map.HasDexRegisterMap());
David Srbeckyfd89b072018-06-03 12:00:22 +0100254 DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map);
255 ASSERT_EQ(number_of_dex_registers, dex_register_map.size());
David Srbeckye1402122018-06-13 18:20:45 +0100256 ASSERT_TRUE(dex_register_map[0].IsLive());
257 ASSERT_TRUE(dex_register_map[1].IsLive());
David Srbecky71ec1cc2018-05-18 15:57:25 +0100258 ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters());
David Brazdild9cb68e2015-08-25 13:52:43 +0100259
David Srbeckye1402122018-06-13 18:20:45 +0100260 ASSERT_EQ(Kind::kInRegister, dex_register_map[0].GetKind());
261 ASSERT_EQ(Kind::kInRegisterHigh, dex_register_map[1].GetKind());
262 ASSERT_EQ(6, dex_register_map[0].GetMachineRegister());
263 ASSERT_EQ(8, dex_register_map[1].GetMachineRegister());
David Brazdild9cb68e2015-08-25 13:52:43 +0100264
David Srbecky71ec1cc2018-05-18 15:57:25 +0100265 DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(4);
266 DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(5);
David Brazdild9cb68e2015-08-25 13:52:43 +0100267 ASSERT_EQ(Kind::kInRegister, location0.GetKind());
268 ASSERT_EQ(Kind::kInRegisterHigh, location1.GetKind());
David Brazdild9cb68e2015-08-25 13:52:43 +0100269 ASSERT_EQ(6, location0.GetValue());
270 ASSERT_EQ(8, location1.GetValue());
271
David Srbecky052f8ca2018-04-26 15:42:54 +0100272 ASSERT_FALSE(stack_map.HasInlineInfo());
David Brazdild9cb68e2015-08-25 13:52:43 +0100273 }
274
275 // Fourth stack map.
276 {
David Srbecky052f8ca2018-04-26 15:42:54 +0100277 StackMap stack_map = code_info.GetStackMapAt(3);
278 ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(3u)));
David Srbeckyd775f962018-05-30 18:12:52 +0100279 ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(256u * kPcAlign)));
David Srbecky052f8ca2018-04-26 15:42:54 +0100280 ASSERT_EQ(3u, stack_map.GetDexPc());
David Srbeckyd775f962018-05-30 18:12:52 +0100281 ASSERT_EQ(256u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA));
David Srbecky052f8ca2018-04-26 15:42:54 +0100282 ASSERT_EQ(0xCDu, code_info.GetRegisterMaskOf(stack_map));
David Brazdild9cb68e2015-08-25 13:52:43 +0100283
David Srbecky052f8ca2018-04-26 15:42:54 +0100284 ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask4));
David Brazdild9cb68e2015-08-25 13:52:43 +0100285
David Srbecky052f8ca2018-04-26 15:42:54 +0100286 ASSERT_TRUE(stack_map.HasDexRegisterMap());
David Srbeckyfd89b072018-06-03 12:00:22 +0100287 DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map);
288 ASSERT_EQ(number_of_dex_registers, dex_register_map.size());
David Srbeckye1402122018-06-13 18:20:45 +0100289 ASSERT_TRUE(dex_register_map[0].IsLive());
290 ASSERT_TRUE(dex_register_map[1].IsLive());
David Srbecky71ec1cc2018-05-18 15:57:25 +0100291 ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters());
David Brazdild9cb68e2015-08-25 13:52:43 +0100292
David Srbeckye1402122018-06-13 18:20:45 +0100293 ASSERT_EQ(Kind::kInFpuRegister, dex_register_map[0].GetKind());
294 ASSERT_EQ(Kind::kInFpuRegisterHigh, dex_register_map[1].GetKind());
295 ASSERT_EQ(3, dex_register_map[0].GetMachineRegister());
296 ASSERT_EQ(1, dex_register_map[1].GetMachineRegister());
David Brazdild9cb68e2015-08-25 13:52:43 +0100297
David Srbecky71ec1cc2018-05-18 15:57:25 +0100298 DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(3);
299 DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(6);
David Brazdild9cb68e2015-08-25 13:52:43 +0100300 ASSERT_EQ(Kind::kInFpuRegister, location0.GetKind());
301 ASSERT_EQ(Kind::kInFpuRegisterHigh, location1.GetKind());
David Brazdild9cb68e2015-08-25 13:52:43 +0100302 ASSERT_EQ(3, location0.GetValue());
303 ASSERT_EQ(1, location1.GetValue());
304
David Srbecky052f8ca2018-04-26 15:42:54 +0100305 ASSERT_FALSE(stack_map.HasInlineInfo());
David Brazdild9cb68e2015-08-25 13:52:43 +0100306 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100307}
308
Mathieu Chartier32289082017-02-09 15:57:37 -0800309TEST(StackMapTest, TestDeduplicateInlineInfoDexRegisterMap) {
David Sehr3215fff2018-04-03 17:10:12 -0700310 MallocArenaPool pool;
Vladimir Marko174b2e22017-10-12 13:34:49 +0100311 ArenaStack arena_stack(&pool);
312 ScopedArenaAllocator allocator(&arena_stack);
Vladimir Marko69d310e2017-10-09 14:12:23 +0100313 StackMapStream stream(&allocator, kRuntimeISA);
Mythri Alled9e83772022-07-14 09:38:49 +0000314 stream.BeginMethod(/* frame_size_in_bytes= */ 32,
315 /* core_spill_mask= */ 0,
316 /* fp_spill_mask= */ 0,
317 /* num_dex_registers= */ 2,
318 /* baseline= */ false,
319 /* debuggable= */ false);
Mathieu Chartier32289082017-02-09 15:57:37 -0800320 ArtMethod art_method;
321
Vladimir Marko69d310e2017-10-09 14:12:23 +0100322 ArenaBitVector sp_mask1(&allocator, 0, true);
Mathieu Chartier32289082017-02-09 15:57:37 -0800323 sp_mask1.SetBit(2);
324 sp_mask1.SetBit(4);
325 const size_t number_of_dex_registers = 2;
326 const size_t number_of_dex_registers_in_inline_info = 2;
David Srbeckyf6ba5b32018-06-23 22:05:49 +0100327 stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask1);
Mathieu Chartier32289082017-02-09 15:57:37 -0800328 stream.AddDexRegisterEntry(Kind::kInStack, 0); // Short location.
329 stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location.
330 stream.BeginInlineInfoEntry(&art_method, 3, number_of_dex_registers_in_inline_info);
331 stream.AddDexRegisterEntry(Kind::kInStack, 0); // Short location.
332 stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location.
333 stream.EndInlineInfoEntry();
334 stream.EndStackMapEntry();
335
David Srbecky17b4d2b2021-03-02 18:14:31 +0000336 stream.EndMethod(64 * kPcAlign);
David Srbeckye7a91942018-08-01 17:23:53 +0100337 ScopedArenaVector<uint8_t> memory = stream.Encode();
Mathieu Chartier32289082017-02-09 15:57:37 -0800338
David Srbeckye7a91942018-08-01 17:23:53 +0100339 CodeInfo code_info(memory.data());
David Srbecky052f8ca2018-04-26 15:42:54 +0100340 ASSERT_EQ(1u, code_info.GetNumberOfStackMaps());
Mathieu Chartier32289082017-02-09 15:57:37 -0800341
David Srbecky052f8ca2018-04-26 15:42:54 +0100342 uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries();
Mathieu Chartier32289082017-02-09 15:57:37 -0800343 ASSERT_EQ(2u, number_of_catalog_entries);
Mathieu Chartier32289082017-02-09 15:57:37 -0800344
345 // First stack map.
346 {
David Srbecky052f8ca2018-04-26 15:42:54 +0100347 StackMap stack_map = code_info.GetStackMapAt(0);
348 ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0)));
David Srbeckyd775f962018-05-30 18:12:52 +0100349 ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64 * kPcAlign)));
David Srbecky052f8ca2018-04-26 15:42:54 +0100350 ASSERT_EQ(0u, stack_map.GetDexPc());
David Srbeckyd775f962018-05-30 18:12:52 +0100351 ASSERT_EQ(64u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA));
David Srbecky052f8ca2018-04-26 15:42:54 +0100352 ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(stack_map));
Mathieu Chartier32289082017-02-09 15:57:37 -0800353
David Srbecky052f8ca2018-04-26 15:42:54 +0100354 ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask1));
Mathieu Chartier32289082017-02-09 15:57:37 -0800355
David Srbecky052f8ca2018-04-26 15:42:54 +0100356 ASSERT_TRUE(stack_map.HasDexRegisterMap());
David Srbeckyfd89b072018-06-03 12:00:22 +0100357 DexRegisterMap map(code_info.GetDexRegisterMapOf(stack_map));
358 ASSERT_EQ(number_of_dex_registers, map.size());
David Srbeckye1402122018-06-13 18:20:45 +0100359 ASSERT_TRUE(map[0].IsLive());
360 ASSERT_TRUE(map[1].IsLive());
David Srbecky71ec1cc2018-05-18 15:57:25 +0100361 ASSERT_EQ(2u, map.GetNumberOfLiveDexRegisters());
Mathieu Chartier32289082017-02-09 15:57:37 -0800362
David Srbeckye1402122018-06-13 18:20:45 +0100363 ASSERT_EQ(Kind::kInStack, map[0].GetKind());
364 ASSERT_EQ(Kind::kConstant, map[1].GetKind());
365 ASSERT_EQ(0, map[0].GetStackOffsetInBytes());
366 ASSERT_EQ(-2, map[1].GetConstant());
Mathieu Chartier32289082017-02-09 15:57:37 -0800367
David Srbecky71ec1cc2018-05-18 15:57:25 +0100368 DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(0);
369 DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(1);
Mathieu Chartier32289082017-02-09 15:57:37 -0800370 ASSERT_EQ(Kind::kInStack, location0.GetKind());
371 ASSERT_EQ(Kind::kConstant, location1.GetKind());
Mathieu Chartier32289082017-02-09 15:57:37 -0800372 ASSERT_EQ(0, location0.GetValue());
373 ASSERT_EQ(-2, location1.GetValue());
Mathieu Chartier32289082017-02-09 15:57:37 -0800374 }
375}
376
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000377TEST(StackMapTest, TestNonLiveDexRegisters) {
David Sehr3215fff2018-04-03 17:10:12 -0700378 MallocArenaPool pool;
Vladimir Marko174b2e22017-10-12 13:34:49 +0100379 ArenaStack arena_stack(&pool);
380 ScopedArenaAllocator allocator(&arena_stack);
Vladimir Marko69d310e2017-10-09 14:12:23 +0100381 StackMapStream stream(&allocator, kRuntimeISA);
Mythri Alled9e83772022-07-14 09:38:49 +0000382 stream.BeginMethod(/* frame_size_in_bytes= */ 32,
383 /* core_spill_mask= */ 0,
384 /* fp_spill_mask= */ 0,
385 /* num_dex_registers= */ 2,
386 /* baseline= */ false,
387 /* debuggable= */ false);
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000388
Vladimir Marko69d310e2017-10-09 14:12:23 +0100389 ArenaBitVector sp_mask(&allocator, 0, false);
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000390 uint32_t number_of_dex_registers = 2;
David Srbeckyf6ba5b32018-06-23 22:05:49 +0100391 stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100392 stream.AddDexRegisterEntry(Kind::kNone, 0); // No location.
393 stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location.
Calin Juravle4f46ac52015-04-23 18:47:21 +0100394 stream.EndStackMapEntry();
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000395
David Srbecky17b4d2b2021-03-02 18:14:31 +0000396 stream.EndMethod(64 * kPcAlign);
David Srbeckye7a91942018-08-01 17:23:53 +0100397 ScopedArenaVector<uint8_t> memory = stream.Encode();
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000398
David Srbeckye7a91942018-08-01 17:23:53 +0100399 CodeInfo code_info(memory.data());
David Srbecky052f8ca2018-04-26 15:42:54 +0100400 ASSERT_EQ(1u, code_info.GetNumberOfStackMaps());
Roland Levillaina552e1c2015-03-26 15:01:03 +0000401
David Srbecky052f8ca2018-04-26 15:42:54 +0100402 uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries();
David Srbecky09ed0982016-02-12 21:58:43 +0000403 ASSERT_EQ(1u, number_of_catalog_entries);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000404
David Srbecky052f8ca2018-04-26 15:42:54 +0100405 StackMap stack_map = code_info.GetStackMapAt(0);
406 ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0)));
David Srbeckyd775f962018-05-30 18:12:52 +0100407 ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64 * kPcAlign)));
David Srbecky052f8ca2018-04-26 15:42:54 +0100408 ASSERT_EQ(0u, stack_map.GetDexPc());
David Srbeckyd775f962018-05-30 18:12:52 +0100409 ASSERT_EQ(64u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA));
David Srbecky052f8ca2018-04-26 15:42:54 +0100410 ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(stack_map));
Roland Levillaina552e1c2015-03-26 15:01:03 +0000411
David Srbecky052f8ca2018-04-26 15:42:54 +0100412 ASSERT_TRUE(stack_map.HasDexRegisterMap());
David Srbeckyfd89b072018-06-03 12:00:22 +0100413 DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map);
414 ASSERT_EQ(number_of_dex_registers, dex_register_map.size());
David Srbeckye1402122018-06-13 18:20:45 +0100415 ASSERT_FALSE(dex_register_map[0].IsLive());
416 ASSERT_TRUE(dex_register_map[1].IsLive());
David Srbecky71ec1cc2018-05-18 15:57:25 +0100417 ASSERT_EQ(1u, dex_register_map.GetNumberOfLiveDexRegisters());
Roland Levillaina552e1c2015-03-26 15:01:03 +0000418
David Srbeckye1402122018-06-13 18:20:45 +0100419 ASSERT_EQ(Kind::kNone, dex_register_map[0].GetKind());
420 ASSERT_EQ(Kind::kConstant, dex_register_map[1].GetKind());
421 ASSERT_EQ(-2, dex_register_map[1].GetConstant());
Roland Levillaina552e1c2015-03-26 15:01:03 +0000422
David Srbecky71ec1cc2018-05-18 15:57:25 +0100423 DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(0);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000424 ASSERT_EQ(Kind::kConstant, location1.GetKind());
Roland Levillaina552e1c2015-03-26 15:01:03 +0000425 ASSERT_EQ(-2, location1.GetValue());
426
David Srbecky052f8ca2018-04-26 15:42:54 +0100427 ASSERT_FALSE(stack_map.HasInlineInfo());
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000428}
429
Calin Juravle6ae70962015-03-18 16:31:28 +0000430TEST(StackMapTest, TestShareDexRegisterMap) {
David Sehr3215fff2018-04-03 17:10:12 -0700431 MallocArenaPool pool;
Vladimir Marko174b2e22017-10-12 13:34:49 +0100432 ArenaStack arena_stack(&pool);
433 ScopedArenaAllocator allocator(&arena_stack);
Vladimir Marko69d310e2017-10-09 14:12:23 +0100434 StackMapStream stream(&allocator, kRuntimeISA);
Mythri Alled9e83772022-07-14 09:38:49 +0000435 stream.BeginMethod(/* frame_size_in_bytes= */ 32,
436 /* core_spill_mask= */ 0,
437 /* fp_spill_mask= */ 0,
438 /* num_dex_registers= */ 2,
439 /* baseline= */ false,
440 /* debuggable= */ false);
Calin Juravle6ae70962015-03-18 16:31:28 +0000441
Vladimir Marko69d310e2017-10-09 14:12:23 +0100442 ArenaBitVector sp_mask(&allocator, 0, false);
Calin Juravle6ae70962015-03-18 16:31:28 +0000443 uint32_t number_of_dex_registers = 2;
444 // First stack map.
David Srbeckyf6ba5b32018-06-23 22:05:49 +0100445 stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100446 stream.AddDexRegisterEntry(Kind::kInRegister, 0); // Short location.
447 stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location.
Calin Juravle4f46ac52015-04-23 18:47:21 +0100448 stream.EndStackMapEntry();
Calin Juravle6ae70962015-03-18 16:31:28 +0000449 // Second stack map, which should share the same dex register map.
David Srbeckyf6ba5b32018-06-23 22:05:49 +0100450 stream.BeginStackMapEntry(0, 65 * kPcAlign, 0x3, &sp_mask);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100451 stream.AddDexRegisterEntry(Kind::kInRegister, 0); // Short location.
452 stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location.
Calin Juravle4f46ac52015-04-23 18:47:21 +0100453 stream.EndStackMapEntry();
Calin Juravle6ae70962015-03-18 16:31:28 +0000454 // Third stack map (doesn't share the dex register map).
David Srbeckyf6ba5b32018-06-23 22:05:49 +0100455 stream.BeginStackMapEntry(0, 66 * kPcAlign, 0x3, &sp_mask);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100456 stream.AddDexRegisterEntry(Kind::kInRegister, 2); // Short location.
457 stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location.
Calin Juravle4f46ac52015-04-23 18:47:21 +0100458 stream.EndStackMapEntry();
Calin Juravle6ae70962015-03-18 16:31:28 +0000459
David Srbecky17b4d2b2021-03-02 18:14:31 +0000460 stream.EndMethod(66 * kPcAlign);
David Srbeckye7a91942018-08-01 17:23:53 +0100461 ScopedArenaVector<uint8_t> memory = stream.Encode();
Calin Juravle6ae70962015-03-18 16:31:28 +0000462
David Srbeckye7a91942018-08-01 17:23:53 +0100463 CodeInfo ci(memory.data());
David Brazdilf677ebf2015-05-29 16:29:43 +0100464
Calin Juravle6ae70962015-03-18 16:31:28 +0000465 // Verify first stack map.
David Srbecky052f8ca2018-04-26 15:42:54 +0100466 StackMap sm0 = ci.GetStackMapAt(0);
David Srbeckyfd89b072018-06-03 12:00:22 +0100467 DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm0);
468 ASSERT_EQ(number_of_dex_registers, dex_registers0.size());
David Srbeckye1402122018-06-13 18:20:45 +0100469 ASSERT_EQ(0, dex_registers0[0].GetMachineRegister());
470 ASSERT_EQ(-2, dex_registers0[1].GetConstant());
Calin Juravle6ae70962015-03-18 16:31:28 +0000471
472 // Verify second stack map.
David Srbecky052f8ca2018-04-26 15:42:54 +0100473 StackMap sm1 = ci.GetStackMapAt(1);
David Srbeckyfd89b072018-06-03 12:00:22 +0100474 DexRegisterMap dex_registers1 = ci.GetDexRegisterMapOf(sm1);
475 ASSERT_EQ(number_of_dex_registers, dex_registers1.size());
David Srbeckye1402122018-06-13 18:20:45 +0100476 ASSERT_EQ(0, dex_registers1[0].GetMachineRegister());
477 ASSERT_EQ(-2, dex_registers1[1].GetConstant());
Calin Juravle6ae70962015-03-18 16:31:28 +0000478
479 // Verify third stack map.
David Srbecky052f8ca2018-04-26 15:42:54 +0100480 StackMap sm2 = ci.GetStackMapAt(2);
David Srbeckyfd89b072018-06-03 12:00:22 +0100481 DexRegisterMap dex_registers2 = ci.GetDexRegisterMapOf(sm2);
482 ASSERT_EQ(number_of_dex_registers, dex_registers2.size());
David Srbeckye1402122018-06-13 18:20:45 +0100483 ASSERT_EQ(2, dex_registers2[0].GetMachineRegister());
484 ASSERT_EQ(-2, dex_registers2[1].GetConstant());
Calin Juravle6ae70962015-03-18 16:31:28 +0000485
David Srbecky6de88332018-06-03 12:00:11 +0100486 // Verify dex register mask offsets.
487 ASSERT_FALSE(sm1.HasDexRegisterMaskIndex()); // No delta.
488 ASSERT_TRUE(sm2.HasDexRegisterMaskIndex()); // Has delta.
Calin Juravle6ae70962015-03-18 16:31:28 +0000489}
490
Roland Levillaina552e1c2015-03-26 15:01:03 +0000491TEST(StackMapTest, TestNoDexRegisterMap) {
David Sehr3215fff2018-04-03 17:10:12 -0700492 MallocArenaPool pool;
Vladimir Marko174b2e22017-10-12 13:34:49 +0100493 ArenaStack arena_stack(&pool);
494 ScopedArenaAllocator allocator(&arena_stack);
Vladimir Marko69d310e2017-10-09 14:12:23 +0100495 StackMapStream stream(&allocator, kRuntimeISA);
Mythri Alled9e83772022-07-14 09:38:49 +0000496 stream.BeginMethod(/* frame_size_in_bytes= */ 32,
497 /* core_spill_mask= */ 0,
498 /* fp_spill_mask= */ 0,
499 /* num_dex_registers= */ 1,
500 /* baseline= */ false,
501 /* debuggable= */ false);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000502
Vladimir Marko69d310e2017-10-09 14:12:23 +0100503 ArenaBitVector sp_mask(&allocator, 0, false);
David Srbeckyf6ba5b32018-06-23 22:05:49 +0100504 stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask);
Calin Juravle4f46ac52015-04-23 18:47:21 +0100505 stream.EndStackMapEntry();
Roland Levillaina552e1c2015-03-26 15:01:03 +0000506
David Srbeckyf6ba5b32018-06-23 22:05:49 +0100507 stream.BeginStackMapEntry(1, 68 * kPcAlign, 0x4, &sp_mask);
David Srbecky71ec1cc2018-05-18 15:57:25 +0100508 stream.AddDexRegisterEntry(Kind::kNone, 0);
Nicolas Geoffray012fc4e2016-01-08 15:58:19 +0000509 stream.EndStackMapEntry();
510
David Srbecky17b4d2b2021-03-02 18:14:31 +0000511 stream.EndMethod(68 * kPcAlign);
David Srbeckye7a91942018-08-01 17:23:53 +0100512 ScopedArenaVector<uint8_t> memory = stream.Encode();
Roland Levillaina552e1c2015-03-26 15:01:03 +0000513
David Srbeckye7a91942018-08-01 17:23:53 +0100514 CodeInfo code_info(memory.data());
David Srbecky052f8ca2018-04-26 15:42:54 +0100515 ASSERT_EQ(2u, code_info.GetNumberOfStackMaps());
Roland Levillaina552e1c2015-03-26 15:01:03 +0000516
David Srbecky052f8ca2018-04-26 15:42:54 +0100517 uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries();
David Srbecky09ed0982016-02-12 21:58:43 +0000518 ASSERT_EQ(0u, number_of_catalog_entries);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000519
David Srbecky052f8ca2018-04-26 15:42:54 +0100520 StackMap stack_map = code_info.GetStackMapAt(0);
521 ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0)));
David Srbeckyd775f962018-05-30 18:12:52 +0100522 ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64 * kPcAlign)));
David Srbecky052f8ca2018-04-26 15:42:54 +0100523 ASSERT_EQ(0u, stack_map.GetDexPc());
David Srbeckyd775f962018-05-30 18:12:52 +0100524 ASSERT_EQ(64u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA));
David Srbecky052f8ca2018-04-26 15:42:54 +0100525 ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(stack_map));
Roland Levillaina552e1c2015-03-26 15:01:03 +0000526
David Srbecky052f8ca2018-04-26 15:42:54 +0100527 ASSERT_FALSE(stack_map.HasDexRegisterMap());
528 ASSERT_FALSE(stack_map.HasInlineInfo());
Nicolas Geoffray012fc4e2016-01-08 15:58:19 +0000529
David Srbecky052f8ca2018-04-26 15:42:54 +0100530 stack_map = code_info.GetStackMapAt(1);
531 ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(1)));
David Srbeckyd775f962018-05-30 18:12:52 +0100532 ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(68 * kPcAlign)));
David Srbecky052f8ca2018-04-26 15:42:54 +0100533 ASSERT_EQ(1u, stack_map.GetDexPc());
David Srbeckyd775f962018-05-30 18:12:52 +0100534 ASSERT_EQ(68u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA));
David Srbecky052f8ca2018-04-26 15:42:54 +0100535 ASSERT_EQ(0x4u, code_info.GetRegisterMaskOf(stack_map));
Nicolas Geoffray012fc4e2016-01-08 15:58:19 +0000536
David Srbecky71ec1cc2018-05-18 15:57:25 +0100537 ASSERT_TRUE(stack_map.HasDexRegisterMap());
David Srbecky052f8ca2018-04-26 15:42:54 +0100538 ASSERT_FALSE(stack_map.HasInlineInfo());
Roland Levillaina552e1c2015-03-26 15:01:03 +0000539}
540
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100541TEST(StackMapTest, InlineTest) {
David Sehr3215fff2018-04-03 17:10:12 -0700542 MallocArenaPool pool;
Vladimir Marko174b2e22017-10-12 13:34:49 +0100543 ArenaStack arena_stack(&pool);
544 ScopedArenaAllocator allocator(&arena_stack);
Vladimir Marko69d310e2017-10-09 14:12:23 +0100545 StackMapStream stream(&allocator, kRuntimeISA);
Mythri Alled9e83772022-07-14 09:38:49 +0000546 stream.BeginMethod(/* frame_size_in_bytes= */ 32,
547 /* core_spill_mask= */ 0,
548 /* fp_spill_mask= */ 0,
549 /* num_dex_registers= */ 2,
550 /* baseline= */ false,
551 /* debuggable= */ false);
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000552 ArtMethod art_method;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100553
Vladimir Marko69d310e2017-10-09 14:12:23 +0100554 ArenaBitVector sp_mask1(&allocator, 0, true);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100555 sp_mask1.SetBit(2);
556 sp_mask1.SetBit(4);
557
558 // First stack map.
David Srbeckyf6ba5b32018-06-23 22:05:49 +0100559 stream.BeginStackMapEntry(0, 10 * kPcAlign, 0x3, &sp_mask1);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100560 stream.AddDexRegisterEntry(Kind::kInStack, 0);
561 stream.AddDexRegisterEntry(Kind::kConstant, 4);
562
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000563 stream.BeginInlineInfoEntry(&art_method, 2, 1);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100564 stream.AddDexRegisterEntry(Kind::kInStack, 8);
565 stream.EndInlineInfoEntry();
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000566 stream.BeginInlineInfoEntry(&art_method, 3, 3);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100567 stream.AddDexRegisterEntry(Kind::kInStack, 16);
568 stream.AddDexRegisterEntry(Kind::kConstant, 20);
569 stream.AddDexRegisterEntry(Kind::kInRegister, 15);
570 stream.EndInlineInfoEntry();
571
572 stream.EndStackMapEntry();
573
574 // Second stack map.
David Srbeckyf6ba5b32018-06-23 22:05:49 +0100575 stream.BeginStackMapEntry(2, 22 * kPcAlign, 0x3, &sp_mask1);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100576 stream.AddDexRegisterEntry(Kind::kInStack, 56);
577 stream.AddDexRegisterEntry(Kind::kConstant, 0);
578
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000579 stream.BeginInlineInfoEntry(&art_method, 2, 1);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100580 stream.AddDexRegisterEntry(Kind::kInStack, 12);
581 stream.EndInlineInfoEntry();
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000582 stream.BeginInlineInfoEntry(&art_method, 3, 3);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100583 stream.AddDexRegisterEntry(Kind::kInStack, 80);
584 stream.AddDexRegisterEntry(Kind::kConstant, 10);
585 stream.AddDexRegisterEntry(Kind::kInRegister, 5);
586 stream.EndInlineInfoEntry();
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000587 stream.BeginInlineInfoEntry(&art_method, 5, 0);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100588 stream.EndInlineInfoEntry();
589
590 stream.EndStackMapEntry();
591
592 // Third stack map.
David Srbeckyf6ba5b32018-06-23 22:05:49 +0100593 stream.BeginStackMapEntry(4, 56 * kPcAlign, 0x3, &sp_mask1);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100594 stream.AddDexRegisterEntry(Kind::kNone, 0);
595 stream.AddDexRegisterEntry(Kind::kConstant, 4);
596 stream.EndStackMapEntry();
597
598 // Fourth stack map.
David Srbeckyf6ba5b32018-06-23 22:05:49 +0100599 stream.BeginStackMapEntry(6, 78 * kPcAlign, 0x3, &sp_mask1);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100600 stream.AddDexRegisterEntry(Kind::kInStack, 56);
601 stream.AddDexRegisterEntry(Kind::kConstant, 0);
602
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000603 stream.BeginInlineInfoEntry(&art_method, 2, 0);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100604 stream.EndInlineInfoEntry();
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000605 stream.BeginInlineInfoEntry(&art_method, 5, 1);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100606 stream.AddDexRegisterEntry(Kind::kInRegister, 2);
607 stream.EndInlineInfoEntry();
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000608 stream.BeginInlineInfoEntry(&art_method, 10, 2);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100609 stream.AddDexRegisterEntry(Kind::kNone, 0);
610 stream.AddDexRegisterEntry(Kind::kInRegister, 3);
611 stream.EndInlineInfoEntry();
612
613 stream.EndStackMapEntry();
614
David Srbecky17b4d2b2021-03-02 18:14:31 +0000615 stream.EndMethod(78 * kPcAlign);
David Srbeckye7a91942018-08-01 17:23:53 +0100616 ScopedArenaVector<uint8_t> memory = stream.Encode();
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100617
David Srbeckye7a91942018-08-01 17:23:53 +0100618 CodeInfo ci(memory.data());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100619
620 {
621 // Verify first stack map.
David Srbecky052f8ca2018-04-26 15:42:54 +0100622 StackMap sm0 = ci.GetStackMapAt(0);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100623
David Srbeckyfd89b072018-06-03 12:00:22 +0100624 DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm0);
625 ASSERT_EQ(2u, dex_registers0.size());
David Srbeckye1402122018-06-13 18:20:45 +0100626 ASSERT_EQ(0, dex_registers0[0].GetStackOffsetInBytes());
627 ASSERT_EQ(4, dex_registers0[1].GetConstant());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100628
David Srbecky93bd3612018-07-02 19:30:18 +0100629 auto inline_infos = ci.GetInlineInfosOf(sm0);
630 ASSERT_EQ(2u, inline_infos.size());
631 ASSERT_EQ(2u, inline_infos[0].GetDexPc());
632 ASSERT_TRUE(inline_infos[0].EncodesArtMethod());
633 ASSERT_EQ(3u, inline_infos[1].GetDexPc());
634 ASSERT_TRUE(inline_infos[1].EncodesArtMethod());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100635
David Srbecky93bd3612018-07-02 19:30:18 +0100636 DexRegisterMap dex_registers1 = ci.GetInlineDexRegisterMapOf(sm0, inline_infos[0]);
David Srbeckyfd89b072018-06-03 12:00:22 +0100637 ASSERT_EQ(1u, dex_registers1.size());
David Srbeckye1402122018-06-13 18:20:45 +0100638 ASSERT_EQ(8, dex_registers1[0].GetStackOffsetInBytes());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100639
David Srbecky93bd3612018-07-02 19:30:18 +0100640 DexRegisterMap dex_registers2 = ci.GetInlineDexRegisterMapOf(sm0, inline_infos[1]);
David Srbeckyfd89b072018-06-03 12:00:22 +0100641 ASSERT_EQ(3u, dex_registers2.size());
David Srbeckye1402122018-06-13 18:20:45 +0100642 ASSERT_EQ(16, dex_registers2[0].GetStackOffsetInBytes());
643 ASSERT_EQ(20, dex_registers2[1].GetConstant());
644 ASSERT_EQ(15, dex_registers2[2].GetMachineRegister());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100645 }
646
647 {
648 // Verify second stack map.
David Srbecky052f8ca2018-04-26 15:42:54 +0100649 StackMap sm1 = ci.GetStackMapAt(1);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100650
David Srbeckyfd89b072018-06-03 12:00:22 +0100651 DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm1);
652 ASSERT_EQ(2u, dex_registers0.size());
David Srbeckye1402122018-06-13 18:20:45 +0100653 ASSERT_EQ(56, dex_registers0[0].GetStackOffsetInBytes());
654 ASSERT_EQ(0, dex_registers0[1].GetConstant());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100655
David Srbecky93bd3612018-07-02 19:30:18 +0100656 auto inline_infos = ci.GetInlineInfosOf(sm1);
657 ASSERT_EQ(3u, inline_infos.size());
658 ASSERT_EQ(2u, inline_infos[0].GetDexPc());
659 ASSERT_TRUE(inline_infos[0].EncodesArtMethod());
660 ASSERT_EQ(3u, inline_infos[1].GetDexPc());
661 ASSERT_TRUE(inline_infos[1].EncodesArtMethod());
662 ASSERT_EQ(5u, inline_infos[2].GetDexPc());
663 ASSERT_TRUE(inline_infos[2].EncodesArtMethod());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100664
David Srbecky93bd3612018-07-02 19:30:18 +0100665 DexRegisterMap dex_registers1 = ci.GetInlineDexRegisterMapOf(sm1, inline_infos[0]);
David Srbeckyfd89b072018-06-03 12:00:22 +0100666 ASSERT_EQ(1u, dex_registers1.size());
David Srbeckye1402122018-06-13 18:20:45 +0100667 ASSERT_EQ(12, dex_registers1[0].GetStackOffsetInBytes());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100668
David Srbecky93bd3612018-07-02 19:30:18 +0100669 DexRegisterMap dex_registers2 = ci.GetInlineDexRegisterMapOf(sm1, inline_infos[1]);
David Srbeckyfd89b072018-06-03 12:00:22 +0100670 ASSERT_EQ(3u, dex_registers2.size());
David Srbeckye1402122018-06-13 18:20:45 +0100671 ASSERT_EQ(80, dex_registers2[0].GetStackOffsetInBytes());
672 ASSERT_EQ(10, dex_registers2[1].GetConstant());
673 ASSERT_EQ(5, dex_registers2[2].GetMachineRegister());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100674 }
675
676 {
677 // Verify third stack map.
David Srbecky052f8ca2018-04-26 15:42:54 +0100678 StackMap sm2 = ci.GetStackMapAt(2);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100679
David Srbeckyfd89b072018-06-03 12:00:22 +0100680 DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm2);
681 ASSERT_EQ(2u, dex_registers0.size());
David Srbeckye1402122018-06-13 18:20:45 +0100682 ASSERT_FALSE(dex_registers0[0].IsLive());
683 ASSERT_EQ(4, dex_registers0[1].GetConstant());
David Srbecky052f8ca2018-04-26 15:42:54 +0100684 ASSERT_FALSE(sm2.HasInlineInfo());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100685 }
686
687 {
688 // Verify fourth stack map.
David Srbecky052f8ca2018-04-26 15:42:54 +0100689 StackMap sm3 = ci.GetStackMapAt(3);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100690
David Srbeckyfd89b072018-06-03 12:00:22 +0100691 DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm3);
692 ASSERT_EQ(2u, dex_registers0.size());
David Srbeckye1402122018-06-13 18:20:45 +0100693 ASSERT_EQ(56, dex_registers0[0].GetStackOffsetInBytes());
694 ASSERT_EQ(0, dex_registers0[1].GetConstant());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100695
David Srbecky93bd3612018-07-02 19:30:18 +0100696 auto inline_infos = ci.GetInlineInfosOf(sm3);
697 ASSERT_EQ(3u, inline_infos.size());
698 ASSERT_EQ(2u, inline_infos[0].GetDexPc());
699 ASSERT_TRUE(inline_infos[0].EncodesArtMethod());
700 ASSERT_EQ(5u, inline_infos[1].GetDexPc());
701 ASSERT_TRUE(inline_infos[1].EncodesArtMethod());
702 ASSERT_EQ(10u, inline_infos[2].GetDexPc());
703 ASSERT_TRUE(inline_infos[2].EncodesArtMethod());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100704
David Srbecky93bd3612018-07-02 19:30:18 +0100705 DexRegisterMap dex_registers1 = ci.GetInlineDexRegisterMapOf(sm3, inline_infos[1]);
David Srbeckyfd89b072018-06-03 12:00:22 +0100706 ASSERT_EQ(1u, dex_registers1.size());
David Srbeckye1402122018-06-13 18:20:45 +0100707 ASSERT_EQ(2, dex_registers1[0].GetMachineRegister());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100708
David Srbecky93bd3612018-07-02 19:30:18 +0100709 DexRegisterMap dex_registers2 = ci.GetInlineDexRegisterMapOf(sm3, inline_infos[2]);
David Srbeckyfd89b072018-06-03 12:00:22 +0100710 ASSERT_EQ(2u, dex_registers2.size());
David Srbeckye1402122018-06-13 18:20:45 +0100711 ASSERT_FALSE(dex_registers2[0].IsLive());
712 ASSERT_EQ(3, dex_registers2[1].GetMachineRegister());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100713 }
714}
715
David Srbeckyd02b23f2018-05-29 23:27:22 +0100716TEST(StackMapTest, PackedNativePcTest) {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100717 // Test minimum alignments, and decoding.
David Srbeckyd02b23f2018-05-29 23:27:22 +0100718 uint32_t packed_thumb2 =
719 StackMap::PackNativePc(kThumb2InstructionAlignment, InstructionSet::kThumb2);
720 uint32_t packed_arm64 =
721 StackMap::PackNativePc(kArm64InstructionAlignment, InstructionSet::kArm64);
722 uint32_t packed_x86 =
723 StackMap::PackNativePc(kX86InstructionAlignment, InstructionSet::kX86);
724 uint32_t packed_x86_64 =
725 StackMap::PackNativePc(kX86_64InstructionAlignment, InstructionSet::kX86_64);
David Srbeckyd02b23f2018-05-29 23:27:22 +0100726 EXPECT_EQ(StackMap::UnpackNativePc(packed_thumb2, InstructionSet::kThumb2),
727 kThumb2InstructionAlignment);
728 EXPECT_EQ(StackMap::UnpackNativePc(packed_arm64, InstructionSet::kArm64),
729 kArm64InstructionAlignment);
730 EXPECT_EQ(StackMap::UnpackNativePc(packed_x86, InstructionSet::kX86),
731 kX86InstructionAlignment);
732 EXPECT_EQ(StackMap::UnpackNativePc(packed_x86_64, InstructionSet::kX86_64),
733 kX86_64InstructionAlignment);
Mathieu Chartiera2f526f2017-01-19 14:48:48 -0800734}
735
David Srbecky45aa5982016-03-18 02:15:09 +0000736TEST(StackMapTest, TestDeduplicateStackMask) {
David Sehr3215fff2018-04-03 17:10:12 -0700737 MallocArenaPool pool;
Vladimir Marko174b2e22017-10-12 13:34:49 +0100738 ArenaStack arena_stack(&pool);
739 ScopedArenaAllocator allocator(&arena_stack);
Vladimir Marko69d310e2017-10-09 14:12:23 +0100740 StackMapStream stream(&allocator, kRuntimeISA);
Mythri Alled9e83772022-07-14 09:38:49 +0000741 stream.BeginMethod(/* frame_size_in_bytes= */ 32,
742 /* core_spill_mask= */ 0,
743 /* fp_spill_mask= */ 0,
744 /* num_dex_registers= */ 0,
745 /* baseline= */ false,
746 /* debuggable= */ false);
David Srbecky45aa5982016-03-18 02:15:09 +0000747
Vladimir Marko69d310e2017-10-09 14:12:23 +0100748 ArenaBitVector sp_mask(&allocator, 0, true);
David Srbecky45aa5982016-03-18 02:15:09 +0000749 sp_mask.SetBit(1);
750 sp_mask.SetBit(4);
David Srbeckyf6ba5b32018-06-23 22:05:49 +0100751 stream.BeginStackMapEntry(0, 4 * kPcAlign, 0x3, &sp_mask);
David Srbecky45aa5982016-03-18 02:15:09 +0000752 stream.EndStackMapEntry();
David Srbeckyf6ba5b32018-06-23 22:05:49 +0100753 stream.BeginStackMapEntry(0, 8 * kPcAlign, 0x3, &sp_mask);
David Srbecky45aa5982016-03-18 02:15:09 +0000754 stream.EndStackMapEntry();
755
David Srbecky17b4d2b2021-03-02 18:14:31 +0000756 stream.EndMethod(8 * kPcAlign);
David Srbeckye7a91942018-08-01 17:23:53 +0100757 ScopedArenaVector<uint8_t> memory = stream.Encode();
David Srbecky45aa5982016-03-18 02:15:09 +0000758
David Srbeckye7a91942018-08-01 17:23:53 +0100759 CodeInfo code_info(memory.data());
David Srbecky052f8ca2018-04-26 15:42:54 +0100760 ASSERT_EQ(2u, code_info.GetNumberOfStackMaps());
David Srbecky45aa5982016-03-18 02:15:09 +0000761
David Srbeckyd775f962018-05-30 18:12:52 +0100762 StackMap stack_map1 = code_info.GetStackMapForNativePcOffset(4 * kPcAlign);
763 StackMap stack_map2 = code_info.GetStackMapForNativePcOffset(8 * kPcAlign);
David Srbecky052f8ca2018-04-26 15:42:54 +0100764 EXPECT_EQ(stack_map1.GetStackMaskIndex(),
765 stack_map2.GetStackMaskIndex());
David Srbecky45aa5982016-03-18 02:15:09 +0000766}
767
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100768} // namespace art