1 /*
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"
18 
19 #include "art_method.h"
20 #include "base/arena_bit_vector.h"
21 #include "base/malloc_arena_pool.h"
22 #include "stack_map_stream.h"
23 
24 #include "gtest/gtest.h"
25 
26 namespace art {
27 
28 // Check that the stack mask of given stack map is identical
29 // to the given bit vector. Returns true if they are same.
CheckStackMask(const CodeInfo & code_info,const StackMap & stack_map,const BitVector & bit_vector)30 static bool CheckStackMask(
31     const CodeInfo& code_info,
32     const StackMap& stack_map,
33     const BitVector& bit_vector) {
34   BitMemoryRegion stack_mask = code_info.GetStackMaskOf(stack_map);
35   if (bit_vector.GetNumberOfBits() > stack_mask.size_in_bits()) {
36     return false;
37   }
38   for (size_t i = 0; i < stack_mask.size_in_bits(); ++i) {
39     if (stack_mask.LoadBit(i) != bit_vector.IsBitSet(i)) {
40       return false;
41     }
42   }
43   return true;
44 }
45 
46 using Kind = DexRegisterLocation::Kind;
47 
48 constexpr static uint32_t kPcAlign = GetInstructionSetInstructionAlignment(kRuntimeISA);
49 
TEST(StackMapTest,Test1)50 TEST(StackMapTest, Test1) {
51   MallocArenaPool pool;
52   ArenaStack arena_stack(&pool);
53   ScopedArenaAllocator allocator(&arena_stack);
54   StackMapStream stream(&allocator, kRuntimeISA);
55   stream.BeginMethod(32, 0, 0, 2);
56 
57   ArenaBitVector sp_mask(&allocator, 0, false);
58   size_t number_of_dex_registers = 2;
59   stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask);
60   stream.AddDexRegisterEntry(Kind::kInStack, 0);         // Short location.
61   stream.AddDexRegisterEntry(Kind::kConstant, -2);       // Short location.
62   stream.EndStackMapEntry();
63 
64   stream.EndMethod();
65   ScopedArenaVector<uint8_t> memory = stream.Encode();
66 
67   CodeInfo code_info(memory.data());
68   ASSERT_EQ(1u, code_info.GetNumberOfStackMaps());
69 
70   uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries();
71   ASSERT_EQ(2u, number_of_catalog_entries);
72 
73   StackMap stack_map = code_info.GetStackMapAt(0);
74   ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0)));
75   ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64 * kPcAlign)));
76   ASSERT_EQ(0u, stack_map.GetDexPc());
77   ASSERT_EQ(64u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA));
78   ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(stack_map));
79 
80   ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask));
81 
82   ASSERT_TRUE(stack_map.HasDexRegisterMap());
83   DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map);
84   ASSERT_EQ(number_of_dex_registers, dex_register_map.size());
85   ASSERT_TRUE(dex_register_map[0].IsLive());
86   ASSERT_TRUE(dex_register_map[1].IsLive());
87   ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters());
88 
89   ASSERT_EQ(Kind::kInStack, dex_register_map[0].GetKind());
90   ASSERT_EQ(Kind::kConstant, dex_register_map[1].GetKind());
91   ASSERT_EQ(0, dex_register_map[0].GetStackOffsetInBytes());
92   ASSERT_EQ(-2, dex_register_map[1].GetConstant());
93 
94   DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(0);
95   DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(1);
96   ASSERT_EQ(Kind::kInStack, location0.GetKind());
97   ASSERT_EQ(Kind::kConstant, location1.GetKind());
98   ASSERT_EQ(0, location0.GetValue());
99   ASSERT_EQ(-2, location1.GetValue());
100 
101   ASSERT_FALSE(stack_map.HasInlineInfo());
102 }
103 
TEST(StackMapTest,Test2)104 TEST(StackMapTest, Test2) {
105   MallocArenaPool pool;
106   ArenaStack arena_stack(&pool);
107   ScopedArenaAllocator allocator(&arena_stack);
108   StackMapStream stream(&allocator, kRuntimeISA);
109   stream.BeginMethod(32, 0, 0, 2);
110   ArtMethod art_method;
111 
112   ArenaBitVector sp_mask1(&allocator, 0, true);
113   sp_mask1.SetBit(2);
114   sp_mask1.SetBit(4);
115   size_t number_of_dex_registers = 2;
116   size_t number_of_dex_registers_in_inline_info = 0;
117   stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask1);
118   stream.AddDexRegisterEntry(Kind::kInStack, 0);         // Short location.
119   stream.AddDexRegisterEntry(Kind::kConstant, -2);       // Large location.
120   stream.BeginInlineInfoEntry(&art_method, 3, number_of_dex_registers_in_inline_info);
121   stream.EndInlineInfoEntry();
122   stream.BeginInlineInfoEntry(&art_method, 2, number_of_dex_registers_in_inline_info);
123   stream.EndInlineInfoEntry();
124   stream.EndStackMapEntry();
125 
126   ArenaBitVector sp_mask2(&allocator, 0, true);
127   sp_mask2.SetBit(3);
128   sp_mask2.SetBit(8);
129   stream.BeginStackMapEntry(1, 128 * kPcAlign, 0xFF, &sp_mask2);
130   stream.AddDexRegisterEntry(Kind::kInRegister, 18);     // Short location.
131   stream.AddDexRegisterEntry(Kind::kInFpuRegister, 3);   // Short location.
132   stream.EndStackMapEntry();
133 
134   ArenaBitVector sp_mask3(&allocator, 0, true);
135   sp_mask3.SetBit(1);
136   sp_mask3.SetBit(5);
137   stream.BeginStackMapEntry(2, 192 * kPcAlign, 0xAB, &sp_mask3);
138   stream.AddDexRegisterEntry(Kind::kInRegister, 6);       // Short location.
139   stream.AddDexRegisterEntry(Kind::kInRegisterHigh, 8);   // Short location.
140   stream.EndStackMapEntry();
141 
142   ArenaBitVector sp_mask4(&allocator, 0, true);
143   sp_mask4.SetBit(6);
144   sp_mask4.SetBit(7);
145   stream.BeginStackMapEntry(3, 256 * kPcAlign, 0xCD, &sp_mask4);
146   stream.AddDexRegisterEntry(Kind::kInFpuRegister, 3);      // Short location, same in stack map 2.
147   stream.AddDexRegisterEntry(Kind::kInFpuRegisterHigh, 1);  // Short location.
148   stream.EndStackMapEntry();
149 
150   stream.EndMethod();
151   ScopedArenaVector<uint8_t> memory = stream.Encode();
152 
153   CodeInfo code_info(memory.data());
154   ASSERT_EQ(4u, code_info.GetNumberOfStackMaps());
155 
156   uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries();
157   ASSERT_EQ(7u, number_of_catalog_entries);
158 
159   // First stack map.
160   {
161     StackMap stack_map = code_info.GetStackMapAt(0);
162     ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0)));
163     ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64 * kPcAlign)));
164     ASSERT_EQ(0u, stack_map.GetDexPc());
165     ASSERT_EQ(64u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA));
166     ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(stack_map));
167 
168     ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask1));
169 
170     ASSERT_TRUE(stack_map.HasDexRegisterMap());
171     DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map);
172     ASSERT_EQ(number_of_dex_registers, dex_register_map.size());
173     ASSERT_TRUE(dex_register_map[0].IsLive());
174     ASSERT_TRUE(dex_register_map[1].IsLive());
175     ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters());
176 
177     ASSERT_EQ(Kind::kInStack, dex_register_map[0].GetKind());
178     ASSERT_EQ(Kind::kConstant, dex_register_map[1].GetKind());
179     ASSERT_EQ(0, dex_register_map[0].GetStackOffsetInBytes());
180     ASSERT_EQ(-2, dex_register_map[1].GetConstant());
181 
182     DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(0);
183     DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(1);
184     ASSERT_EQ(Kind::kInStack, location0.GetKind());
185     ASSERT_EQ(Kind::kConstant, location1.GetKind());
186     ASSERT_EQ(0, location0.GetValue());
187     ASSERT_EQ(-2, location1.GetValue());
188 
189     ASSERT_TRUE(stack_map.HasInlineInfo());
190     auto inline_infos = code_info.GetInlineInfosOf(stack_map);
191     ASSERT_EQ(2u, inline_infos.size());
192     ASSERT_EQ(3u, inline_infos[0].GetDexPc());
193     ASSERT_EQ(2u, inline_infos[1].GetDexPc());
194     ASSERT_TRUE(inline_infos[0].EncodesArtMethod());
195     ASSERT_TRUE(inline_infos[1].EncodesArtMethod());
196   }
197 
198   // Second stack map.
199   {
200     StackMap stack_map = code_info.GetStackMapAt(1);
201     ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(1u)));
202     ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(128u * kPcAlign)));
203     ASSERT_EQ(1u, stack_map.GetDexPc());
204     ASSERT_EQ(128u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA));
205     ASSERT_EQ(0xFFu, code_info.GetRegisterMaskOf(stack_map));
206 
207     ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask2));
208 
209     ASSERT_TRUE(stack_map.HasDexRegisterMap());
210     DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map);
211     ASSERT_EQ(number_of_dex_registers, dex_register_map.size());
212     ASSERT_TRUE(dex_register_map[0].IsLive());
213     ASSERT_TRUE(dex_register_map[1].IsLive());
214     ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters());
215 
216     ASSERT_EQ(Kind::kInRegister, dex_register_map[0].GetKind());
217     ASSERT_EQ(Kind::kInFpuRegister, dex_register_map[1].GetKind());
218     ASSERT_EQ(18, dex_register_map[0].GetMachineRegister());
219     ASSERT_EQ(3, dex_register_map[1].GetMachineRegister());
220 
221     DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(2);
222     DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(3);
223     ASSERT_EQ(Kind::kInRegister, location0.GetKind());
224     ASSERT_EQ(Kind::kInFpuRegister, location1.GetKind());
225     ASSERT_EQ(18, location0.GetValue());
226     ASSERT_EQ(3, location1.GetValue());
227 
228     ASSERT_FALSE(stack_map.HasInlineInfo());
229   }
230 
231   // Third stack map.
232   {
233     StackMap stack_map = code_info.GetStackMapAt(2);
234     ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(2u)));
235     ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(192u * kPcAlign)));
236     ASSERT_EQ(2u, stack_map.GetDexPc());
237     ASSERT_EQ(192u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA));
238     ASSERT_EQ(0xABu, code_info.GetRegisterMaskOf(stack_map));
239 
240     ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask3));
241 
242     ASSERT_TRUE(stack_map.HasDexRegisterMap());
243     DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map);
244     ASSERT_EQ(number_of_dex_registers, dex_register_map.size());
245     ASSERT_TRUE(dex_register_map[0].IsLive());
246     ASSERT_TRUE(dex_register_map[1].IsLive());
247     ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters());
248 
249     ASSERT_EQ(Kind::kInRegister, dex_register_map[0].GetKind());
250     ASSERT_EQ(Kind::kInRegisterHigh, dex_register_map[1].GetKind());
251     ASSERT_EQ(6, dex_register_map[0].GetMachineRegister());
252     ASSERT_EQ(8, dex_register_map[1].GetMachineRegister());
253 
254     DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(4);
255     DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(5);
256     ASSERT_EQ(Kind::kInRegister, location0.GetKind());
257     ASSERT_EQ(Kind::kInRegisterHigh, location1.GetKind());
258     ASSERT_EQ(6, location0.GetValue());
259     ASSERT_EQ(8, location1.GetValue());
260 
261     ASSERT_FALSE(stack_map.HasInlineInfo());
262   }
263 
264   // Fourth stack map.
265   {
266     StackMap stack_map = code_info.GetStackMapAt(3);
267     ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(3u)));
268     ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(256u * kPcAlign)));
269     ASSERT_EQ(3u, stack_map.GetDexPc());
270     ASSERT_EQ(256u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA));
271     ASSERT_EQ(0xCDu, code_info.GetRegisterMaskOf(stack_map));
272 
273     ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask4));
274 
275     ASSERT_TRUE(stack_map.HasDexRegisterMap());
276     DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map);
277     ASSERT_EQ(number_of_dex_registers, dex_register_map.size());
278     ASSERT_TRUE(dex_register_map[0].IsLive());
279     ASSERT_TRUE(dex_register_map[1].IsLive());
280     ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters());
281 
282     ASSERT_EQ(Kind::kInFpuRegister, dex_register_map[0].GetKind());
283     ASSERT_EQ(Kind::kInFpuRegisterHigh, dex_register_map[1].GetKind());
284     ASSERT_EQ(3, dex_register_map[0].GetMachineRegister());
285     ASSERT_EQ(1, dex_register_map[1].GetMachineRegister());
286 
287     DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(3);
288     DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(6);
289     ASSERT_EQ(Kind::kInFpuRegister, location0.GetKind());
290     ASSERT_EQ(Kind::kInFpuRegisterHigh, location1.GetKind());
291     ASSERT_EQ(3, location0.GetValue());
292     ASSERT_EQ(1, location1.GetValue());
293 
294     ASSERT_FALSE(stack_map.HasInlineInfo());
295   }
296 }
297 
TEST(StackMapTest,TestDeduplicateInlineInfoDexRegisterMap)298 TEST(StackMapTest, TestDeduplicateInlineInfoDexRegisterMap) {
299   MallocArenaPool pool;
300   ArenaStack arena_stack(&pool);
301   ScopedArenaAllocator allocator(&arena_stack);
302   StackMapStream stream(&allocator, kRuntimeISA);
303   stream.BeginMethod(32, 0, 0, 2);
304   ArtMethod art_method;
305 
306   ArenaBitVector sp_mask1(&allocator, 0, true);
307   sp_mask1.SetBit(2);
308   sp_mask1.SetBit(4);
309   const size_t number_of_dex_registers = 2;
310   const size_t number_of_dex_registers_in_inline_info = 2;
311   stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask1);
312   stream.AddDexRegisterEntry(Kind::kInStack, 0);         // Short location.
313   stream.AddDexRegisterEntry(Kind::kConstant, -2);       // Large location.
314   stream.BeginInlineInfoEntry(&art_method, 3, number_of_dex_registers_in_inline_info);
315   stream.AddDexRegisterEntry(Kind::kInStack, 0);         // Short location.
316   stream.AddDexRegisterEntry(Kind::kConstant, -2);       // Large location.
317   stream.EndInlineInfoEntry();
318   stream.EndStackMapEntry();
319 
320   stream.EndMethod();
321   ScopedArenaVector<uint8_t> memory = stream.Encode();
322 
323   CodeInfo code_info(memory.data());
324   ASSERT_EQ(1u, code_info.GetNumberOfStackMaps());
325 
326   uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries();
327   ASSERT_EQ(2u, number_of_catalog_entries);
328 
329   // First stack map.
330   {
331     StackMap stack_map = code_info.GetStackMapAt(0);
332     ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0)));
333     ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64 * kPcAlign)));
334     ASSERT_EQ(0u, stack_map.GetDexPc());
335     ASSERT_EQ(64u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA));
336     ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(stack_map));
337 
338     ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask1));
339 
340     ASSERT_TRUE(stack_map.HasDexRegisterMap());
341     DexRegisterMap map(code_info.GetDexRegisterMapOf(stack_map));
342     ASSERT_EQ(number_of_dex_registers, map.size());
343     ASSERT_TRUE(map[0].IsLive());
344     ASSERT_TRUE(map[1].IsLive());
345     ASSERT_EQ(2u, map.GetNumberOfLiveDexRegisters());
346 
347     ASSERT_EQ(Kind::kInStack, map[0].GetKind());
348     ASSERT_EQ(Kind::kConstant, map[1].GetKind());
349     ASSERT_EQ(0, map[0].GetStackOffsetInBytes());
350     ASSERT_EQ(-2, map[1].GetConstant());
351 
352     DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(0);
353     DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(1);
354     ASSERT_EQ(Kind::kInStack, location0.GetKind());
355     ASSERT_EQ(Kind::kConstant, location1.GetKind());
356     ASSERT_EQ(0, location0.GetValue());
357     ASSERT_EQ(-2, location1.GetValue());
358   }
359 }
360 
TEST(StackMapTest,TestNonLiveDexRegisters)361 TEST(StackMapTest, TestNonLiveDexRegisters) {
362   MallocArenaPool pool;
363   ArenaStack arena_stack(&pool);
364   ScopedArenaAllocator allocator(&arena_stack);
365   StackMapStream stream(&allocator, kRuntimeISA);
366   stream.BeginMethod(32, 0, 0, 2);
367 
368   ArenaBitVector sp_mask(&allocator, 0, false);
369   uint32_t number_of_dex_registers = 2;
370   stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask);
371   stream.AddDexRegisterEntry(Kind::kNone, 0);            // No location.
372   stream.AddDexRegisterEntry(Kind::kConstant, -2);       // Large location.
373   stream.EndStackMapEntry();
374 
375   stream.EndMethod();
376   ScopedArenaVector<uint8_t> memory = stream.Encode();
377 
378   CodeInfo code_info(memory.data());
379   ASSERT_EQ(1u, code_info.GetNumberOfStackMaps());
380 
381   uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries();
382   ASSERT_EQ(1u, number_of_catalog_entries);
383 
384   StackMap stack_map = code_info.GetStackMapAt(0);
385   ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0)));
386   ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64 * kPcAlign)));
387   ASSERT_EQ(0u, stack_map.GetDexPc());
388   ASSERT_EQ(64u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA));
389   ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(stack_map));
390 
391   ASSERT_TRUE(stack_map.HasDexRegisterMap());
392   DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map);
393   ASSERT_EQ(number_of_dex_registers, dex_register_map.size());
394   ASSERT_FALSE(dex_register_map[0].IsLive());
395   ASSERT_TRUE(dex_register_map[1].IsLive());
396   ASSERT_EQ(1u, dex_register_map.GetNumberOfLiveDexRegisters());
397 
398   ASSERT_EQ(Kind::kNone, dex_register_map[0].GetKind());
399   ASSERT_EQ(Kind::kConstant, dex_register_map[1].GetKind());
400   ASSERT_EQ(-2, dex_register_map[1].GetConstant());
401 
402   DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(0);
403   ASSERT_EQ(Kind::kConstant, location1.GetKind());
404   ASSERT_EQ(-2, location1.GetValue());
405 
406   ASSERT_FALSE(stack_map.HasInlineInfo());
407 }
408 
TEST(StackMapTest,TestShareDexRegisterMap)409 TEST(StackMapTest, TestShareDexRegisterMap) {
410   MallocArenaPool pool;
411   ArenaStack arena_stack(&pool);
412   ScopedArenaAllocator allocator(&arena_stack);
413   StackMapStream stream(&allocator, kRuntimeISA);
414   stream.BeginMethod(32, 0, 0, 2);
415 
416   ArenaBitVector sp_mask(&allocator, 0, false);
417   uint32_t number_of_dex_registers = 2;
418   // First stack map.
419   stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask);
420   stream.AddDexRegisterEntry(Kind::kInRegister, 0);  // Short location.
421   stream.AddDexRegisterEntry(Kind::kConstant, -2);   // Large location.
422   stream.EndStackMapEntry();
423   // Second stack map, which should share the same dex register map.
424   stream.BeginStackMapEntry(0, 65 * kPcAlign, 0x3, &sp_mask);
425   stream.AddDexRegisterEntry(Kind::kInRegister, 0);  // Short location.
426   stream.AddDexRegisterEntry(Kind::kConstant, -2);   // Large location.
427   stream.EndStackMapEntry();
428   // Third stack map (doesn't share the dex register map).
429   stream.BeginStackMapEntry(0, 66 * kPcAlign, 0x3, &sp_mask);
430   stream.AddDexRegisterEntry(Kind::kInRegister, 2);  // Short location.
431   stream.AddDexRegisterEntry(Kind::kConstant, -2);   // Large location.
432   stream.EndStackMapEntry();
433 
434   stream.EndMethod();
435   ScopedArenaVector<uint8_t> memory = stream.Encode();
436 
437   CodeInfo ci(memory.data());
438 
439   // Verify first stack map.
440   StackMap sm0 = ci.GetStackMapAt(0);
441   DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm0);
442   ASSERT_EQ(number_of_dex_registers, dex_registers0.size());
443   ASSERT_EQ(0, dex_registers0[0].GetMachineRegister());
444   ASSERT_EQ(-2, dex_registers0[1].GetConstant());
445 
446   // Verify second stack map.
447   StackMap sm1 = ci.GetStackMapAt(1);
448   DexRegisterMap dex_registers1 = ci.GetDexRegisterMapOf(sm1);
449   ASSERT_EQ(number_of_dex_registers, dex_registers1.size());
450   ASSERT_EQ(0, dex_registers1[0].GetMachineRegister());
451   ASSERT_EQ(-2, dex_registers1[1].GetConstant());
452 
453   // Verify third stack map.
454   StackMap sm2 = ci.GetStackMapAt(2);
455   DexRegisterMap dex_registers2 = ci.GetDexRegisterMapOf(sm2);
456   ASSERT_EQ(number_of_dex_registers, dex_registers2.size());
457   ASSERT_EQ(2, dex_registers2[0].GetMachineRegister());
458   ASSERT_EQ(-2, dex_registers2[1].GetConstant());
459 
460   // Verify dex register mask offsets.
461   ASSERT_FALSE(sm1.HasDexRegisterMaskIndex());  // No delta.
462   ASSERT_TRUE(sm2.HasDexRegisterMaskIndex());  // Has delta.
463 }
464 
TEST(StackMapTest,TestNoDexRegisterMap)465 TEST(StackMapTest, TestNoDexRegisterMap) {
466   MallocArenaPool pool;
467   ArenaStack arena_stack(&pool);
468   ScopedArenaAllocator allocator(&arena_stack);
469   StackMapStream stream(&allocator, kRuntimeISA);
470   stream.BeginMethod(32, 0, 0, 1);
471 
472   ArenaBitVector sp_mask(&allocator, 0, false);
473   uint32_t number_of_dex_registers = 0;
474   stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask);
475   stream.EndStackMapEntry();
476 
477   number_of_dex_registers = 1;
478   stream.BeginStackMapEntry(1, 68 * kPcAlign, 0x4, &sp_mask);
479   stream.AddDexRegisterEntry(Kind::kNone, 0);
480   stream.EndStackMapEntry();
481 
482   stream.EndMethod();
483   ScopedArenaVector<uint8_t> memory = stream.Encode();
484 
485   CodeInfo code_info(memory.data());
486   ASSERT_EQ(2u, code_info.GetNumberOfStackMaps());
487 
488   uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries();
489   ASSERT_EQ(0u, number_of_catalog_entries);
490 
491   StackMap stack_map = code_info.GetStackMapAt(0);
492   ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0)));
493   ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64 * kPcAlign)));
494   ASSERT_EQ(0u, stack_map.GetDexPc());
495   ASSERT_EQ(64u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA));
496   ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(stack_map));
497 
498   ASSERT_FALSE(stack_map.HasDexRegisterMap());
499   ASSERT_FALSE(stack_map.HasInlineInfo());
500 
501   stack_map = code_info.GetStackMapAt(1);
502   ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(1)));
503   ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(68 * kPcAlign)));
504   ASSERT_EQ(1u, stack_map.GetDexPc());
505   ASSERT_EQ(68u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA));
506   ASSERT_EQ(0x4u, code_info.GetRegisterMaskOf(stack_map));
507 
508   ASSERT_TRUE(stack_map.HasDexRegisterMap());
509   ASSERT_FALSE(stack_map.HasInlineInfo());
510 }
511 
TEST(StackMapTest,InlineTest)512 TEST(StackMapTest, InlineTest) {
513   MallocArenaPool pool;
514   ArenaStack arena_stack(&pool);
515   ScopedArenaAllocator allocator(&arena_stack);
516   StackMapStream stream(&allocator, kRuntimeISA);
517   stream.BeginMethod(32, 0, 0, 2);
518   ArtMethod art_method;
519 
520   ArenaBitVector sp_mask1(&allocator, 0, true);
521   sp_mask1.SetBit(2);
522   sp_mask1.SetBit(4);
523 
524   // First stack map.
525   stream.BeginStackMapEntry(0, 10 * kPcAlign, 0x3, &sp_mask1);
526   stream.AddDexRegisterEntry(Kind::kInStack, 0);
527   stream.AddDexRegisterEntry(Kind::kConstant, 4);
528 
529   stream.BeginInlineInfoEntry(&art_method, 2, 1);
530   stream.AddDexRegisterEntry(Kind::kInStack, 8);
531   stream.EndInlineInfoEntry();
532   stream.BeginInlineInfoEntry(&art_method, 3, 3);
533   stream.AddDexRegisterEntry(Kind::kInStack, 16);
534   stream.AddDexRegisterEntry(Kind::kConstant, 20);
535   stream.AddDexRegisterEntry(Kind::kInRegister, 15);
536   stream.EndInlineInfoEntry();
537 
538   stream.EndStackMapEntry();
539 
540   // Second stack map.
541   stream.BeginStackMapEntry(2, 22 * kPcAlign, 0x3, &sp_mask1);
542   stream.AddDexRegisterEntry(Kind::kInStack, 56);
543   stream.AddDexRegisterEntry(Kind::kConstant, 0);
544 
545   stream.BeginInlineInfoEntry(&art_method, 2, 1);
546   stream.AddDexRegisterEntry(Kind::kInStack, 12);
547   stream.EndInlineInfoEntry();
548   stream.BeginInlineInfoEntry(&art_method, 3, 3);
549   stream.AddDexRegisterEntry(Kind::kInStack, 80);
550   stream.AddDexRegisterEntry(Kind::kConstant, 10);
551   stream.AddDexRegisterEntry(Kind::kInRegister, 5);
552   stream.EndInlineInfoEntry();
553   stream.BeginInlineInfoEntry(&art_method, 5, 0);
554   stream.EndInlineInfoEntry();
555 
556   stream.EndStackMapEntry();
557 
558   // Third stack map.
559   stream.BeginStackMapEntry(4, 56 * kPcAlign, 0x3, &sp_mask1);
560   stream.AddDexRegisterEntry(Kind::kNone, 0);
561   stream.AddDexRegisterEntry(Kind::kConstant, 4);
562   stream.EndStackMapEntry();
563 
564   // Fourth stack map.
565   stream.BeginStackMapEntry(6, 78 * kPcAlign, 0x3, &sp_mask1);
566   stream.AddDexRegisterEntry(Kind::kInStack, 56);
567   stream.AddDexRegisterEntry(Kind::kConstant, 0);
568 
569   stream.BeginInlineInfoEntry(&art_method, 2, 0);
570   stream.EndInlineInfoEntry();
571   stream.BeginInlineInfoEntry(&art_method, 5, 1);
572   stream.AddDexRegisterEntry(Kind::kInRegister, 2);
573   stream.EndInlineInfoEntry();
574   stream.BeginInlineInfoEntry(&art_method, 10, 2);
575   stream.AddDexRegisterEntry(Kind::kNone, 0);
576   stream.AddDexRegisterEntry(Kind::kInRegister, 3);
577   stream.EndInlineInfoEntry();
578 
579   stream.EndStackMapEntry();
580 
581   stream.EndMethod();
582   ScopedArenaVector<uint8_t> memory = stream.Encode();
583 
584   CodeInfo ci(memory.data());
585 
586   {
587     // Verify first stack map.
588     StackMap sm0 = ci.GetStackMapAt(0);
589 
590     DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm0);
591     ASSERT_EQ(2u, dex_registers0.size());
592     ASSERT_EQ(0, dex_registers0[0].GetStackOffsetInBytes());
593     ASSERT_EQ(4, dex_registers0[1].GetConstant());
594 
595     auto inline_infos = ci.GetInlineInfosOf(sm0);
596     ASSERT_EQ(2u, inline_infos.size());
597     ASSERT_EQ(2u, inline_infos[0].GetDexPc());
598     ASSERT_TRUE(inline_infos[0].EncodesArtMethod());
599     ASSERT_EQ(3u, inline_infos[1].GetDexPc());
600     ASSERT_TRUE(inline_infos[1].EncodesArtMethod());
601 
602     DexRegisterMap dex_registers1 = ci.GetInlineDexRegisterMapOf(sm0, inline_infos[0]);
603     ASSERT_EQ(1u, dex_registers1.size());
604     ASSERT_EQ(8, dex_registers1[0].GetStackOffsetInBytes());
605 
606     DexRegisterMap dex_registers2 = ci.GetInlineDexRegisterMapOf(sm0, inline_infos[1]);
607     ASSERT_EQ(3u, dex_registers2.size());
608     ASSERT_EQ(16, dex_registers2[0].GetStackOffsetInBytes());
609     ASSERT_EQ(20, dex_registers2[1].GetConstant());
610     ASSERT_EQ(15, dex_registers2[2].GetMachineRegister());
611   }
612 
613   {
614     // Verify second stack map.
615     StackMap sm1 = ci.GetStackMapAt(1);
616 
617     DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm1);
618     ASSERT_EQ(2u, dex_registers0.size());
619     ASSERT_EQ(56, dex_registers0[0].GetStackOffsetInBytes());
620     ASSERT_EQ(0, dex_registers0[1].GetConstant());
621 
622     auto inline_infos = ci.GetInlineInfosOf(sm1);
623     ASSERT_EQ(3u, inline_infos.size());
624     ASSERT_EQ(2u, inline_infos[0].GetDexPc());
625     ASSERT_TRUE(inline_infos[0].EncodesArtMethod());
626     ASSERT_EQ(3u, inline_infos[1].GetDexPc());
627     ASSERT_TRUE(inline_infos[1].EncodesArtMethod());
628     ASSERT_EQ(5u, inline_infos[2].GetDexPc());
629     ASSERT_TRUE(inline_infos[2].EncodesArtMethod());
630 
631     DexRegisterMap dex_registers1 = ci.GetInlineDexRegisterMapOf(sm1, inline_infos[0]);
632     ASSERT_EQ(1u, dex_registers1.size());
633     ASSERT_EQ(12, dex_registers1[0].GetStackOffsetInBytes());
634 
635     DexRegisterMap dex_registers2 = ci.GetInlineDexRegisterMapOf(sm1, inline_infos[1]);
636     ASSERT_EQ(3u, dex_registers2.size());
637     ASSERT_EQ(80, dex_registers2[0].GetStackOffsetInBytes());
638     ASSERT_EQ(10, dex_registers2[1].GetConstant());
639     ASSERT_EQ(5, dex_registers2[2].GetMachineRegister());
640   }
641 
642   {
643     // Verify third stack map.
644     StackMap sm2 = ci.GetStackMapAt(2);
645 
646     DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm2);
647     ASSERT_EQ(2u, dex_registers0.size());
648     ASSERT_FALSE(dex_registers0[0].IsLive());
649     ASSERT_EQ(4, dex_registers0[1].GetConstant());
650     ASSERT_FALSE(sm2.HasInlineInfo());
651   }
652 
653   {
654     // Verify fourth stack map.
655     StackMap sm3 = ci.GetStackMapAt(3);
656 
657     DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm3);
658     ASSERT_EQ(2u, dex_registers0.size());
659     ASSERT_EQ(56, dex_registers0[0].GetStackOffsetInBytes());
660     ASSERT_EQ(0, dex_registers0[1].GetConstant());
661 
662     auto inline_infos = ci.GetInlineInfosOf(sm3);
663     ASSERT_EQ(3u, inline_infos.size());
664     ASSERT_EQ(2u, inline_infos[0].GetDexPc());
665     ASSERT_TRUE(inline_infos[0].EncodesArtMethod());
666     ASSERT_EQ(5u, inline_infos[1].GetDexPc());
667     ASSERT_TRUE(inline_infos[1].EncodesArtMethod());
668     ASSERT_EQ(10u, inline_infos[2].GetDexPc());
669     ASSERT_TRUE(inline_infos[2].EncodesArtMethod());
670 
671     DexRegisterMap dex_registers1 = ci.GetInlineDexRegisterMapOf(sm3, inline_infos[1]);
672     ASSERT_EQ(1u, dex_registers1.size());
673     ASSERT_EQ(2, dex_registers1[0].GetMachineRegister());
674 
675     DexRegisterMap dex_registers2 = ci.GetInlineDexRegisterMapOf(sm3, inline_infos[2]);
676     ASSERT_EQ(2u, dex_registers2.size());
677     ASSERT_FALSE(dex_registers2[0].IsLive());
678     ASSERT_EQ(3, dex_registers2[1].GetMachineRegister());
679   }
680 }
681 
TEST(StackMapTest,PackedNativePcTest)682 TEST(StackMapTest, PackedNativePcTest) {
683   // Test minimum alignments, and decoding.
684   uint32_t packed_thumb2 =
685       StackMap::PackNativePc(kThumb2InstructionAlignment, InstructionSet::kThumb2);
686   uint32_t packed_arm64 =
687       StackMap::PackNativePc(kArm64InstructionAlignment, InstructionSet::kArm64);
688   uint32_t packed_x86 =
689       StackMap::PackNativePc(kX86InstructionAlignment, InstructionSet::kX86);
690   uint32_t packed_x86_64 =
691       StackMap::PackNativePc(kX86_64InstructionAlignment, InstructionSet::kX86_64);
692   EXPECT_EQ(StackMap::UnpackNativePc(packed_thumb2, InstructionSet::kThumb2),
693             kThumb2InstructionAlignment);
694   EXPECT_EQ(StackMap::UnpackNativePc(packed_arm64, InstructionSet::kArm64),
695             kArm64InstructionAlignment);
696   EXPECT_EQ(StackMap::UnpackNativePc(packed_x86, InstructionSet::kX86),
697             kX86InstructionAlignment);
698   EXPECT_EQ(StackMap::UnpackNativePc(packed_x86_64, InstructionSet::kX86_64),
699             kX86_64InstructionAlignment);
700 }
701 
TEST(StackMapTest,TestDeduplicateStackMask)702 TEST(StackMapTest, TestDeduplicateStackMask) {
703   MallocArenaPool pool;
704   ArenaStack arena_stack(&pool);
705   ScopedArenaAllocator allocator(&arena_stack);
706   StackMapStream stream(&allocator, kRuntimeISA);
707   stream.BeginMethod(32, 0, 0, 0);
708 
709   ArenaBitVector sp_mask(&allocator, 0, true);
710   sp_mask.SetBit(1);
711   sp_mask.SetBit(4);
712   stream.BeginStackMapEntry(0, 4 * kPcAlign, 0x3, &sp_mask);
713   stream.EndStackMapEntry();
714   stream.BeginStackMapEntry(0, 8 * kPcAlign, 0x3, &sp_mask);
715   stream.EndStackMapEntry();
716 
717   stream.EndMethod();
718   ScopedArenaVector<uint8_t> memory = stream.Encode();
719 
720   CodeInfo code_info(memory.data());
721   ASSERT_EQ(2u, code_info.GetNumberOfStackMaps());
722 
723   StackMap stack_map1 = code_info.GetStackMapForNativePcOffset(4 * kPcAlign);
724   StackMap stack_map2 = code_info.GetStackMapForNativePcOffset(8 * kPcAlign);
725   EXPECT_EQ(stack_map1.GetStackMaskIndex(),
726             stack_map2.GetStackMaskIndex());
727 }
728 
TEST(StackMapTest,TestDedupeBitTables)729 TEST(StackMapTest, TestDedupeBitTables) {
730   MallocArenaPool pool;
731   ArenaStack arena_stack(&pool);
732   ScopedArenaAllocator allocator(&arena_stack);
733   StackMapStream stream(&allocator, kRuntimeISA);
734   stream.BeginMethod(32, 0, 0, 2);
735 
736   stream.BeginStackMapEntry(0, 64 * kPcAlign);
737   stream.AddDexRegisterEntry(Kind::kInStack, 0);
738   stream.AddDexRegisterEntry(Kind::kConstant, -2);
739   stream.EndStackMapEntry();
740 
741   stream.EndMethod();
742   ScopedArenaVector<uint8_t> memory = stream.Encode();
743 
744   std::vector<uint8_t> out;
745   CodeInfo::Deduper deduper(&out);
746   size_t deduped1 = deduper.Dedupe(memory.data());
747   size_t deduped2 = deduper.Dedupe(memory.data());
748 
749   for (size_t deduped : { deduped1, deduped2 }) {
750     CodeInfo code_info(out.data() + deduped);
751     ASSERT_EQ(1u, code_info.GetNumberOfStackMaps());
752 
753     StackMap stack_map = code_info.GetStackMapAt(0);
754     ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0)));
755     ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64 * kPcAlign)));
756     ASSERT_EQ(0u, stack_map.GetDexPc());
757     ASSERT_EQ(64u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA));
758 
759     ASSERT_TRUE(stack_map.HasDexRegisterMap());
760     DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map);
761 
762     ASSERT_EQ(Kind::kInStack, dex_register_map[0].GetKind());
763     ASSERT_EQ(Kind::kConstant, dex_register_map[1].GetKind());
764     ASSERT_EQ(0, dex_register_map[0].GetStackOffsetInBytes());
765     ASSERT_EQ(-2, dex_register_map[1].GetConstant());
766   }
767 
768   ASSERT_GT(memory.size() * 2, out.size());
769 }
770 
771 }  // namespace art
772