• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 #ifndef ART_RUNTIME_VMAP_TABLE_H_
18 #define ART_RUNTIME_VMAP_TABLE_H_
19 
20 #include "base/logging.h"
21 #include "leb128.h"
22 #include "stack.h"
23 
24 namespace art {
25 
26 class VmapTable {
27  public:
VmapTable(const uint8_t * table)28   explicit VmapTable(const uint8_t* table) : table_(table) {
29   }
30 
31   // Look up nth entry, not called from performance critical code.
32   uint16_t operator[](size_t n) const {
33     const uint8_t* table = table_;
34     size_t size = DecodeUnsignedLeb128(&table);
35     CHECK_LT(n, size);
36     uint16_t entry = DecodeUnsignedLeb128(&table);
37     for (size_t i = 0; i < n; ++i) {
38       entry = DecodeUnsignedLeb128(&table);
39     }
40     return entry;
41   }
42 
Size()43   size_t Size() const {
44     const uint8_t* table = table_;
45     return DecodeUnsignedLeb128(&table);
46   }
47 
48   // Is the dex register 'vreg' in the context or on the stack? Should not be called when the
49   // 'kind' is unknown or constant.
IsInContext(size_t vreg,VRegKind kind,uint32_t * vmap_offset)50   bool IsInContext(size_t vreg, VRegKind kind, uint32_t* vmap_offset) const {
51     DCHECK(kind == kReferenceVReg || kind == kIntVReg || kind == kFloatVReg ||
52            kind == kLongLoVReg || kind == kLongHiVReg || kind == kDoubleLoVReg ||
53            kind == kDoubleHiVReg || kind == kImpreciseConstant);
54     *vmap_offset = 0xEBAD0FF5;
55     // TODO: take advantage of the registers being ordered
56     // TODO: we treat kImpreciseConstant as an integer below, need to ensure that such values
57     //       are never promoted to floating point registers.
58     bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
59     bool in_floats = false;
60     const uint8_t* table = table_;
61     size_t end = DecodeUnsignedLeb128(&table);
62     for (size_t i = 0; i < end; ++i) {
63       // Stop if we find what we are are looking for.
64       uint16_t entry = DecodeUnsignedLeb128(&table);
65       if ((entry == vreg) && (in_floats == is_float)) {
66         *vmap_offset = i;
67         return true;
68       }
69       // 0xffff is the marker for LR (return PC on x86), following it are spilled float registers.
70       if (entry == 0xffff) {
71         in_floats = true;
72       }
73     }
74     return false;
75   }
76 
77   // Compute the register number that corresponds to the entry in the vmap (vmap_offset, computed
78   // by IsInContext above). If the kind is floating point then the result will be a floating point
79   // register number, otherwise it will be an integer register number.
ComputeRegister(uint32_t spill_mask,uint32_t vmap_offset,VRegKind kind)80   uint32_t ComputeRegister(uint32_t spill_mask, uint32_t vmap_offset, VRegKind kind) const {
81     // Compute the register we need to load from the context.
82     DCHECK(kind == kReferenceVReg || kind == kIntVReg || kind == kFloatVReg ||
83            kind == kLongLoVReg || kind == kLongHiVReg || kind == kDoubleLoVReg ||
84            kind == kDoubleHiVReg || kind == kImpreciseConstant);
85     // TODO: we treat kImpreciseConstant as an integer below, need to ensure that such values
86     //       are never promoted to floating point registers.
87     bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
88     uint32_t matches = 0;
89     if (UNLIKELY(is_float)) {
90       const uint8_t* table = table_;
91       DecodeUnsignedLeb128(&table);  // Skip size.
92       while (DecodeUnsignedLeb128(&table) != 0xffff) {
93         matches++;
94       }
95       matches++;
96     }
97     CHECK_LT(vmap_offset - matches, static_cast<uint32_t>(__builtin_popcount(spill_mask)));
98     uint32_t spill_shifts = 0;
99     while (matches != (vmap_offset + 1)) {
100       DCHECK_NE(spill_mask, 0u);
101       matches += spill_mask & 1;  // Add 1 if the low bit is set
102       spill_mask >>= 1;
103       spill_shifts++;
104     }
105     spill_shifts--;  // wind back one as we want the last match
106     return spill_shifts;
107   }
108 
109  private:
110   const uint8_t* const table_;
111 };
112 
113 }  // namespace art
114 
115 #endif  // ART_RUNTIME_VMAP_TABLE_H_
116