Add "kind" argument to Get/SetVReg.
In order to determine where a register is promoted its necessary to know
the kind of use of the register.
Extend notion of precise-ness to numeric verifier register types.
Dump verifier output in oatdump.
Dump vregs with their location or constant value.
Introduce indenting ostream utility.
Change-Id: Ia3d29497877976bc24465484743bca08236e1768
diff --git a/src/stack.h b/src/stack.h
index fd2fd15..5b5609c 100644
--- a/src/stack.h
+++ b/src/stack.h
@@ -29,12 +29,27 @@
namespace art {
class AbstractMethod;
+class Context;
class Object;
class ShadowFrame;
class StackIndirectReferenceTable;
class ScopedObjectAccess;
class Thread;
+// The kind of vreg being accessed in calls to Set/GetVReg.
+enum VRegKind {
+ kReferenceVReg,
+ kIntVReg,
+ kFloatVReg,
+ kLongLoVReg,
+ kLongHiVReg,
+ kDoubleLoVReg,
+ kDoubleHiVReg,
+ kConstant,
+ kImpreciseConstant,
+ kUndefined,
+};
+
class ShadowFrame {
public:
static ShadowFrame* Create(uint16_t num_refs, uint16_t num_vregs, ShadowFrame* link,
@@ -366,15 +381,17 @@
return num_frames_;
}
- uint32_t GetVReg(AbstractMethod* m, int vreg) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ uint32_t GetVReg(AbstractMethod* m, uint16_t vreg, VRegKind kind) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void SetVReg(AbstractMethod* m, int vreg, uint32_t new_value)
+ void SetVReg(AbstractMethod* m, uint16_t vreg, uint32_t new_value, VRegKind kind)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
uintptr_t GetGPR(uint32_t reg) const;
uint32_t GetVReg(AbstractMethod** cur_quick_frame, const DexFile::CodeItem* code_item,
- uint32_t core_spills, uint32_t fp_spills, size_t frame_size, int vreg) const {
+ uint32_t core_spills, uint32_t fp_spills, size_t frame_size,
+ uint16_t vreg) const {
int offset = GetVRegOffset(code_item, core_spills, fp_spills, frame_size, vreg);
DCHECK_EQ(cur_quick_frame, GetCurrentQuickFrame());
byte* vreg_addr = reinterpret_cast<byte*>(cur_quick_frame) + offset;
@@ -482,6 +499,77 @@
Context* const context_;
};
+class VmapTable {
+ public:
+ explicit VmapTable(const uint16_t* table) : table_(table) {
+ }
+
+ uint16_t operator[](size_t i) const {
+ return table_[i + 1];
+ }
+
+ size_t size() const {
+ return table_[0];
+ }
+
+ // Is the dex register 'vreg' in the context or on the stack? Should not be called when the
+ // 'kind' is unknown or constant.
+ bool IsInContext(size_t vreg, uint32_t& vmap_offset, VRegKind kind) const {
+ DCHECK(kind == kReferenceVReg || kind == kIntVReg || kind == kFloatVReg ||
+ kind == kLongLoVReg || kind == kLongHiVReg || kind == kDoubleLoVReg ||
+ kind == kDoubleHiVReg || kind == kImpreciseConstant);
+ vmap_offset = 0xEBAD0FF5;
+ // TODO: take advantage of the registers being ordered
+ // TODO: we treat kImpreciseConstant as an integer below, need to ensure that such values
+ // are never promoted to floating point registers.
+ bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
+ bool in_floats = false;
+ for (size_t i = 0; i < size(); ++i) {
+ // Stop if we find what we are are looking for.
+ if ((table_[i + 1] == vreg) && (in_floats == is_float)) {
+ vmap_offset = i;
+ return true;
+ }
+ // 0xffff is the marker for LR (return PC on x86), following it are spilled float registers.
+ if (table_[i + 1] == 0xffff) {
+ in_floats = true;
+ }
+ }
+ return false;
+ }
+
+ // Compute the register number that corresponds to the entry in the vmap (vmap_offset, computed
+ // by IsInContext above). If the kind is floating point then the result will be a floating point
+ // register number, otherwise it will be an integer register number.
+ uint32_t ComputeRegister(uint32_t spill_mask, uint32_t vmap_offset, VRegKind kind) const {
+ // Compute the register we need to load from the context.
+ DCHECK(kind == kReferenceVReg || kind == kIntVReg || kind == kFloatVReg ||
+ kind == kLongLoVReg || kind == kLongHiVReg || kind == kDoubleLoVReg ||
+ kind == kDoubleHiVReg || kind == kImpreciseConstant);
+ // TODO: we treat kImpreciseConstant as an integer below, need to ensure that such values
+ // are never promoted to floating point registers.
+ bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
+ uint32_t matches = 0;
+ if (is_float) {
+ while (table_[matches] != 0xffff) {
+ matches++;
+ }
+ }
+ CHECK_LT(vmap_offset - matches, static_cast<uint32_t>(__builtin_popcount(spill_mask)));
+ uint32_t spill_shifts = 0;
+ while (matches != (vmap_offset + 1)) {
+ DCHECK_NE(spill_mask, 0u);
+ matches += spill_mask & 1; // Add 1 if the low bit is set
+ spill_mask >>= 1;
+ spill_shifts++;
+ }
+ spill_shifts--; // wind back one as we want the last match
+ return spill_shifts;
+ }
+ private:
+ const uint16_t* table_;
+};
+
} // namespace art
#endif // ART_SRC_STACK_H_