Defer reporting of certain verifier failures.
The verifier currently reports all failures immediately. Certain failures,
such as the failure to resolve a method, or the determination that access
to a field is not allowed, are supposed to deferred until the first time
that executing code does something that could cause the resolution.
With this change, several kinds of verification failures are deferred.
This is done by making a writable copy of the bytecode and replacing the
failing instruction with an "always throw" opcode.
Gory details:
- Added throw-verification-error instruction. Implemented in "portable"
and ARM interpreters. x86 uses portable form through stub.
- Added a function that creates a copy of a DexCode area and makes the
bytecodes writable.
- Added code that replaces a single instruction with an "always throw".
- Replaced runtime check for abstract/interface in new-instance with a
check at verification time.
- Added a test to exercise the deferred error mechanism.
- Minor cleanups (replaced tab, bad valgrind command, ...).
diff --git a/vm/oo/Object.h b/vm/oo/Object.h
index 18fbb36..0bf2728 100644
--- a/vm/oo/Object.h
+++ b/vm/oo/Object.h
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* Declaration of the fundamental Object type and refinements thereof, plus
* some functions for manipulating them.
@@ -93,6 +94,44 @@
#define EXPECTED_FILE_FLAGS \
(ACC_CLASS_MASK | CLASS_ISPREVERIFIED | CLASS_ISOPTIMIZED)
+/*
+ * Get/set class flags.
+ */
+#define SET_CLASS_FLAG(clazz, flag) \
+ do { (clazz)->accessFlags |= (flag); } while (0)
+
+#define CLEAR_CLASS_FLAG(clazz, flag) \
+ do { (clazz)->accessFlags &= ~(flag); } while (0)
+
+#define IS_CLASS_FLAG_SET(clazz, flag) \
+ (((clazz)->accessFlags & (flag)) != 0)
+
+#define GET_CLASS_FLAG_GROUP(clazz, flags) \
+ ((u4)((clazz)->accessFlags & (flags)))
+
+/*
+ * Use the top 16 bits of the access flags field for other method flags.
+ * Code should use the *METHOD_FLAG*() macros to set/get these flags.
+ */
+typedef enum MethodFlags {
+ METHOD_ISWRITABLE = (1<<31), // the method's code is writable
+} MethodFlags;
+
+/*
+ * Get/set method flags.
+ */
+#define SET_METHOD_FLAG(method, flag) \
+ do { (method)->accessFlags |= (flag); } while (0)
+
+#define CLEAR_METHOD_FLAG(method, flag) \
+ do { (method)->accessFlags &= ~(flag); } while (0)
+
+#define IS_METHOD_FLAG_SET(method, flag) \
+ (((method)->accessFlags & (flag)) != 0)
+
+#define GET_METHOD_FLAG_GROUP(method, flags) \
+ ((u4)((method)->accessFlags & (flags)))
+
/* current state of the class, increasing as we progress */
typedef enum ClassStatus {
CLASS_ERROR = -1,
@@ -134,14 +173,6 @@
#define PRIM_TYPE_TO_LETTER "ZCFDBSIJV" /* must match order in enum */
/*
- * This defines the amount of space we leave for field slots in the
- * java.lang.Class definition. If we alter the class to have more than
- * this many fields, the VM will abort at startup.
- */
-#define CLASS_FIELD_SLOTS 4
-
-
-/*
* Used for iftable in ClassObject.
*/
typedef struct InterfaceEntry {
@@ -185,21 +216,6 @@
do { (obj)->clazz = (clazz_); DVM_LOCK_INIT(&(obj)->lock); } while (0)
/*
- * Get/set class flags.
- */
-#define SET_CLASS_FLAG(clazz, flag) \
- do { (clazz)->accessFlags |= (flag); } while (0)
-
-#define CLEAR_CLASS_FLAG(clazz, flag) \
- do { (clazz)->accessFlags &= ~(flag); } while (0)
-
-#define IS_CLASS_FLAG_SET(clazz, flag) \
- (((clazz)->accessFlags & (flag)) != 0)
-
-#define GET_CLASS_FLAG_GROUP(clazz, flags) \
- ((u4)((clazz)->accessFlags & (flags)))
-
-/*
* Data objects have an Object header followed by their instance data.
*/
struct DataObject {
@@ -262,6 +278,13 @@
};
/*
+ * This defines the amount of space we leave for field slots in the
+ * java.lang.Class definition. If we alter the class to have more than
+ * this many fields, the VM will abort at startup.
+ */
+#define CLASS_FIELD_SLOTS 4
+
+/*
* Class objects have many additional fields. This is used for both
* classes and interfaces, including synthesized classes (arrays and
* primitive types).