Verifier clean up.
This is the first part in trying to move to a more rigorous mode of
asserting the validity of garbage collection maps.
In the bring over of the verifier from Dalvik a large class had been
created where all of the Dalvik/Dex functions were static methods of
that class. This rewrite introduces 3 key classes, Verifier that
orchestrates the verification of a method, RegisterLine which describes
the types associated with registers for a particular PC and RegType
which describes the current type of a register within a line. The
functionality is brought over from Dalvik but cleaned up to not do
things like goto. Failing within the verifier is also cleaned up. By
virtue of having stateful objects the interfaces between different
aspects of the verifier are greatly simplified.
To save space, RegTypes are cached upto a maximum possible 2^16, and
given an Id. As the number of RegTypes is typically small this means
that we have a full OO implementation but at a lower space cost than the
current convention that uses botched together enum values requiring
32bits of storage in a RegisterLine rather than 16bits (ie half the
space requirement per register in a register line). To make use of
this space more rigorous monitor verification is brought back, and
ultimately I think we can work around bug 3215458 with richer RegTypes
that are aware of literal objects.
The code removes short cuts that had been added to Dalvik's verifier and
appear illegitimate, it also fixes a large number of bugs in the
description of the verifier.
Where possible the spaghetti of code is replaced with straight line
if-then-elsif.. code that clearly follows the ordering semantics of the
specification. The code is also aiming toward having a more type
rigorous description of the verification process, and when this isn't
possible following the description convention of the specification.
Change-Id: Id25b742018a2ad5ea95687973cca610d7e19513c
diff --git a/src/object.h b/src/object.h
index 882c025..752d405 100644
--- a/src/object.h
+++ b/src/object.h
@@ -538,14 +538,6 @@
void SetName(String* new_name);
- ByteArray* GetRegisterMapData() const;
-
- void SetRegisterMapData(ByteArray* data);
-
- ByteArray* GetRegisterMapHeader() const;
-
- void SetRegisterMapHeader(ByteArray* header);
-
String* GetShorty() const;
void SetShorty(String* new_shorty);
@@ -857,6 +849,14 @@
SetVmapTable(reinterpret_cast<uint16_t*>(vmap_table_offset));
}
+ Object* GetGcMap() const {
+ return GetFieldObject<Object*>(OFFSET_OF_OBJECT_MEMBER(Method, gc_map_), false);
+ }
+
+ void SetGcMap(Object* data) {
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, gc_map_), data, false);
+ }
+
size_t GetFrameSizeInBytes() const {
DCHECK_EQ(sizeof(size_t), sizeof(uint32_t));
size_t result = GetField32(OFFSET_OF_OBJECT_MEMBER(Method, frame_size_in_bytes_), false);
@@ -872,15 +872,7 @@
}
size_t GetReturnPcOffsetInBytes() const {
- DCHECK_EQ(sizeof(size_t), sizeof(uint32_t));
- return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, return_pc_offset_in_bytes_), false);
- }
-
- void SetReturnPcOffsetInBytes(size_t return_pc_offset_in_bytes) {
- DCHECK_EQ(sizeof(size_t), sizeof(uint32_t));
- DCHECK_LT(return_pc_offset_in_bytes, GetFrameSizeInBytes());
- SetField32(OFFSET_OF_OBJECT_MEMBER(Method, return_pc_offset_in_bytes_),
- return_pc_offset_in_bytes, false);
+ return GetFrameSizeInBytes() - kPointerSize;
}
bool IsRegistered() const;
@@ -1043,9 +1035,8 @@
// short cuts to declaring_class_->dex_cache_ member for fast compiled code access
ObjectArray<String>* dex_cache_strings_;
- // Byte arrays that hold data for the register maps
- const ByteArray* register_map_data_;
- const ByteArray* register_map_header_;
+ // Garbage collection map
+ Object* gc_map_;
// The short-form method descriptor string.
String* shorty_;
@@ -1089,6 +1080,7 @@
// Index of the return type
uint32_t java_return_type_idx_;
+ // Mapping from native pc to dex pc
const uint32_t* mapping_table_;
// For concrete virtual methods, this is the offset of the method in Class::vtable_.
@@ -1111,9 +1103,9 @@
// Method prototype descriptor string (return and argument types).
uint32_t proto_idx_;
- // Offset of return PC within frame for compiled code (in bytes)
- size_t return_pc_offset_in_bytes_;
-
+ // When a register is promoted into a register, the spill mask holds which registers hold dex
+ // registers. The first promoted register's corresponding dex register is vmap_table_[1], the Nth
+ // is vmap_table_[N]. vmap_table_[0] holds the length of the table.
const uint16_t* vmap_table_;
uint32_t java_slot_;
@@ -1443,8 +1435,19 @@
return GetPrimitiveType() == kPrimVoid;
}
+ size_t PrimitiveFieldSize() const;
+
size_t PrimitiveSize() const;
+ // Depth of class from java.lang.Object
+ size_t Depth() {
+ size_t depth = 0;
+ for(Class* klass = this; klass->GetSuperClass() != NULL; klass = klass->GetSuperClass()) {
+ depth++;
+ }
+ return depth;
+ }
+
bool IsArrayClass() const {
return GetComponentType() != NULL;
}
@@ -1558,6 +1561,11 @@
bool IsSubClass(const Class* klass) const;
+ // Can src be assigned to this class? For example, String can be assigned to Object (by an
+ // upcast), however, an Object cannot be assigned to a String as a potentially exception throwing
+ // downcast would be necessary. Similarly for interfaces, a class that implements (or an interface
+ // that extends) another can be assigned to its parent, but not vice-versa. All Classes may assign
+ // to themselves. Classes for primitive types may not assign to each other.
bool IsAssignableFrom(const Class* src) const {
DCHECK(src != NULL);
if (this == src) {
@@ -1571,7 +1579,7 @@
} else if (src->IsArrayClass()) {
return IsAssignableFromArray(src);
} else {
- return src->IsSubClass(this);
+ return !src->IsInterface() && src->IsSubClass(this);
}
}
@@ -2535,22 +2543,6 @@
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, name_), new_name, false);
}
-inline ByteArray* Method::GetRegisterMapData() const {
- return GetFieldObject<ByteArray*>(OFFSET_OF_OBJECT_MEMBER(Method, register_map_data_), false);
-}
-
-inline void Method::SetRegisterMapData(ByteArray* data) {
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, register_map_data_), data, false);
-}
-
-inline ByteArray* Method::GetRegisterMapHeader() const {
- return GetFieldObject<ByteArray*>(OFFSET_OF_OBJECT_MEMBER(Method, register_map_header_), false);
-}
-
-inline void Method::SetRegisterMapHeader(ByteArray* header) {
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, register_map_header_), header, false);
-}
-
inline String* Method::GetShorty() const {
DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
return GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Method, shorty_), false);