summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--compiler/driver/compiler_driver.cc6
-rw-r--r--compiler/oat_writer.cc2
-rw-r--r--oatdump/oatdump.cc8
-rw-r--r--runtime/class_linker.cc7
-rw-r--r--runtime/dex_file.h38
-rw-r--r--runtime/dex_file_verifier.cc19
-rw-r--r--runtime/image.cc2
-rw-r--r--runtime/modifiers.h101
-rw-r--r--runtime/verifier/method_verifier.cc4
-rw-r--r--test/121-modifiers/build34
-rw-r--r--test/121-modifiers/classes/A$B.classbin0 -> 223 bytes
-rw-r--r--test/121-modifiers/classes/A$C.classbin0 -> 130 bytes
-rw-r--r--test/121-modifiers/classes/A.classbin0 -> 248 bytes
-rw-r--r--test/121-modifiers/classes/Inf.classbin0 -> 128 bytes
-rw-r--r--test/121-modifiers/classes/Main.classbin0 -> 3772 bytes
-rw-r--r--test/121-modifiers/classes/NonInf.classbin0 -> 1026 bytes
-rw-r--r--test/121-modifiers/expected.txt0
-rw-r--r--test/121-modifiers/info.txt1
-rw-r--r--test/121-modifiers/src/Asm.java125
-rw-r--r--test/121-modifiers/src/Inf.java21
-rw-r--r--test/121-modifiers/src/Main.java211
-rw-r--r--test/121-modifiers/src/NonInf.java72
22 files changed, 586 insertions, 65 deletions
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index bbd19396cd..01e0ac4abe 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1605,7 +1605,7 @@ static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manag
// We require a constructor barrier if there are final instance fields.
requires_constructor_barrier = false;
while (it.HasNextInstanceField()) {
- if ((it.GetMemberAccessFlags() & kAccFinal) != 0) {
+ if (it.MemberIsFinal()) {
requires_constructor_barrier = true;
}
if (resolve_fields_and_methods) {
@@ -1946,7 +1946,7 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz
continue;
}
previous_direct_method_idx = method_idx;
- driver->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
+ driver->CompileMethod(it.GetMethodCodeItem(), it.GetMethodAccessFlags(),
it.GetMethodInvokeType(class_def), class_def_index,
method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level);
it.Next();
@@ -1962,7 +1962,7 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz
continue;
}
previous_virtual_method_idx = method_idx;
- driver->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
+ driver->CompileMethod(it.GetMethodCodeItem(), it.GetMethodAccessFlags(),
it.GetMethodInvokeType(class_def), class_def_index,
method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level);
it.Next();
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index c5d1478a43..e74d6de4eb 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -437,7 +437,7 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor {
std::vector<uint8_t> const * gc_map = compiled_method->GetGcMap();
if (gc_map != nullptr) {
size_t gc_map_size = gc_map->size() * sizeof(gc_map[0]);
- bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0;
+ bool is_native = it.MemberIsNative();
CHECK(gc_map_size != 0 || is_native || status < mirror::Class::kStatusVerified)
<< gc_map << " " << gc_map_size << " " << (is_native ? "true" : "false") << " "
<< (status < mirror::Class::kStatusVerified) << " " << status << " "
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 6ca0bcdb16..f1c00632bc 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -220,14 +220,14 @@ class OatSymbolizer : public CodeOutput {
while (it.HasNextDirectMethod()) {
const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx);
WalkOatMethod(class_def, class_method_idx, oat_method, dex_file, it.GetMemberIndex(),
- it.GetMethodCodeItem(), it.GetMemberAccessFlags(), callback);
+ it.GetMethodCodeItem(), it.GetMethodAccessFlags(), callback);
class_method_idx++;
it.Next();
}
while (it.HasNextVirtualMethod()) {
const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx);
WalkOatMethod(class_def, class_method_idx, oat_method, dex_file, it.GetMemberIndex(),
- it.GetMethodCodeItem(), it.GetMemberAccessFlags(), callback);
+ it.GetMethodCodeItem(), it.GetMethodAccessFlags(), callback);
class_method_idx++;
it.Next();
}
@@ -570,14 +570,14 @@ class OatDumper {
while (it.HasNextDirectMethod()) {
const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx);
DumpOatMethod(os, class_def, class_method_idx, oat_method, dex_file,
- it.GetMemberIndex(), it.GetMethodCodeItem(), it.GetMemberAccessFlags());
+ it.GetMemberIndex(), it.GetMethodCodeItem(), it.GetRawMemberAccessFlags());
class_method_idx++;
it.Next();
}
while (it.HasNextVirtualMethod()) {
const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx);
DumpOatMethod(os, class_def, class_method_idx, oat_method, dex_file,
- it.GetMemberIndex(), it.GetMethodCodeItem(), it.GetMemberAccessFlags());
+ it.GetMemberIndex(), it.GetMethodCodeItem(), it.GetRawMemberAccessFlags());
class_method_idx++;
it.Next();
}
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 4474f1be5b..6a6286fbe2 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2792,8 +2792,7 @@ void ClassLinker::LoadClass(Thread* self, const DexFile& dex_file,
if (kUseBakerOrBrooksReadBarrier) {
klass->AssertReadBarrierPointer();
}
- uint32_t access_flags = dex_class_def.access_flags_;
- // Make sure that none of our runtime-only flags are set.
+ uint32_t access_flags = dex_class_def.GetJavaAccessFlags();
CHECK_EQ(access_flags & ~kAccJavaFlagsMask, 0U);
klass->SetAccessFlags(access_flags);
klass->SetClassLoader(class_loader);
@@ -2936,7 +2935,7 @@ void ClassLinker::LoadField(const DexFile& /*dex_file*/, const ClassDataItemIter
uint32_t field_idx = it.GetMemberIndex();
dst->SetDexFieldIndex(field_idx);
dst->SetDeclaringClass(klass.Get());
- dst->SetAccessFlags(it.GetMemberAccessFlags());
+ dst->SetAccessFlags(it.GetFieldAccessFlags());
}
mirror::ArtMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file,
@@ -2962,7 +2961,7 @@ mirror::ArtMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file
dst->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods());
dst->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes());
- uint32_t access_flags = it.GetMemberAccessFlags();
+ uint32_t access_flags = it.GetMethodAccessFlags();
if (UNLIKELY(strcmp("finalize", method_name) == 0)) {
// Set finalizable flag on declaring class.
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 1cec264be0..c160253019 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -201,6 +201,24 @@ class DexFile {
uint32_t class_data_off_; // file offset to class_data_item
uint32_t static_values_off_; // file offset to EncodedArray
+ // Returns the valid access flags, that is, Java modifier bits relevant to the ClassDef type
+ // (class or interface). These are all in the lower 16b and do not contain runtime flags.
+ uint32_t GetJavaAccessFlags() const {
+ // Make sure that none of our runtime-only flags are set.
+ COMPILE_ASSERT((kAccValidClassFlags & kAccJavaFlagsMask) == kAccValidClassFlags,
+ valid_class_flags_not_subset_of_java_flags);
+ COMPILE_ASSERT((kAccValidInterfaceFlags & kAccJavaFlagsMask) == kAccValidInterfaceFlags,
+ valid_interface_flags_not_subset_of_java_flags);
+
+ if ((access_flags_ & kAccInterface) != 0) {
+ // Interface.
+ return access_flags_ & kAccValidInterfaceFlags;
+ } else {
+ // Class.
+ return access_flags_ & kAccValidClassFlags;
+ }
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(ClassDef);
};
@@ -1112,7 +1130,7 @@ class ClassDataItemIterator {
return last_idx_ + method_.method_idx_delta_;
}
}
- uint32_t GetMemberAccessFlags() const {
+ uint32_t GetRawMemberAccessFlags() const {
if (pos_ < EndOfInstanceFieldsPos()) {
return field_.access_flags_;
} else {
@@ -1120,18 +1138,30 @@ class ClassDataItemIterator {
return method_.access_flags_;
}
}
+ uint32_t GetFieldAccessFlags() const {
+ return GetRawMemberAccessFlags() & kAccValidFieldFlags;
+ }
+ uint32_t GetMethodAccessFlags() const {
+ return GetRawMemberAccessFlags() & kAccValidMethodFlags;
+ }
+ bool MemberIsNative() const {
+ return GetRawMemberAccessFlags() & kAccNative;
+ }
+ bool MemberIsFinal() const {
+ return GetRawMemberAccessFlags() & kAccFinal;
+ }
InvokeType GetMethodInvokeType(const DexFile::ClassDef& class_def) const {
if (HasNextDirectMethod()) {
- if ((GetMemberAccessFlags() & kAccStatic) != 0) {
+ if ((GetRawMemberAccessFlags() & kAccStatic) != 0) {
return kStatic;
} else {
return kDirect;
}
} else {
- DCHECK_EQ(GetMemberAccessFlags() & kAccStatic, 0U);
+ DCHECK_EQ(GetRawMemberAccessFlags() & kAccStatic, 0U);
if ((class_def.access_flags_ & kAccInterface) != 0) {
return kInterface;
- } else if ((GetMemberAccessFlags() & kAccConstructor) != 0) {
+ } else if ((GetRawMemberAccessFlags() & kAccConstructor) != 0) {
return kSuper;
} else {
return kVirtual;
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 976cac9422..9eba92f8f1 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -456,9 +456,7 @@ bool DexFileVerifier::CheckClassDataItemField(uint32_t idx, uint32_t access_flag
return false;
}
- uint32_t access_field_mask = kAccPublic | kAccPrivate | kAccProtected | kAccStatic |
- kAccFinal | kAccVolatile | kAccTransient | kAccSynthetic | kAccEnum;
- if (UNLIKELY((access_flags & ~access_field_mask) != 0)) {
+ if (UNLIKELY((access_flags & ~kAccJavaFlagsMask) != 0)) {
ErrorStringPrintf("Bad class_data_item field access_flags %x", access_flags);
return false;
}
@@ -482,9 +480,8 @@ bool DexFileVerifier::CheckClassDataItemMethod(uint32_t idx, uint32_t access_fla
return false;
}
- uint32_t access_method_mask = kAccPublic | kAccPrivate | kAccProtected | kAccStatic |
- kAccFinal | kAccSynchronized | kAccBridge | kAccVarargs | kAccNative | kAccAbstract |
- kAccStrict | kAccSynthetic | kAccConstructor | kAccDeclaredSynchronized;
+ constexpr uint32_t access_method_mask = kAccJavaFlagsMask | kAccConstructor |
+ kAccDeclaredSynchronized;
if (UNLIKELY(((access_flags & ~access_method_mask) != 0) ||
(is_synchronized && !allow_synchronized))) {
ErrorStringPrintf("Bad class_data_item method access_flags %x", access_flags);
@@ -686,24 +683,26 @@ bool DexFileVerifier::CheckEncodedAnnotation() {
bool DexFileVerifier::CheckIntraClassDataItem() {
ClassDataItemIterator it(*dex_file_, ptr_);
+ // These calls use the raw access flags to check whether the whole dex field is valid.
+
for (; it.HasNextStaticField(); it.Next()) {
- if (!CheckClassDataItemField(it.GetMemberIndex(), it.GetMemberAccessFlags(), true)) {
+ if (!CheckClassDataItemField(it.GetMemberIndex(), it.GetRawMemberAccessFlags(), true)) {
return false;
}
}
for (; it.HasNextInstanceField(); it.Next()) {
- if (!CheckClassDataItemField(it.GetMemberIndex(), it.GetMemberAccessFlags(), false)) {
+ if (!CheckClassDataItemField(it.GetMemberIndex(), it.GetRawMemberAccessFlags(), false)) {
return false;
}
}
for (; it.HasNextDirectMethod(); it.Next()) {
- if (!CheckClassDataItemMethod(it.GetMemberIndex(), it.GetMemberAccessFlags(),
+ if (!CheckClassDataItemMethod(it.GetMemberIndex(), it.GetRawMemberAccessFlags(),
it.GetMethodCodeItemOffset(), true)) {
return false;
}
}
for (; it.HasNextVirtualMethod(); it.Next()) {
- if (!CheckClassDataItemMethod(it.GetMemberIndex(), it.GetMemberAccessFlags(),
+ if (!CheckClassDataItemMethod(it.GetMemberIndex(), it.GetRawMemberAccessFlags(),
it.GetMethodCodeItemOffset(), false)) {
return false;
}
diff --git a/runtime/image.cc b/runtime/image.cc
index 93ec27daf1..478b486d91 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -24,7 +24,7 @@
namespace art {
const byte ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const byte ImageHeader::kImageVersion[] = { '0', '0', '8', '\0' };
+const byte ImageHeader::kImageVersion[] = { '0', '0', '9', '\0' };
ImageHeader::ImageHeader(uint32_t image_begin,
uint32_t image_size,
diff --git a/runtime/modifiers.h b/runtime/modifiers.h
index 2814ed8cad..23c18f86ff 100644
--- a/runtime/modifiers.h
+++ b/runtime/modifiers.h
@@ -19,48 +19,77 @@
#include <stdint.h>
-static const uint32_t kAccPublic = 0x0001; // class, field, method, ic
-static const uint32_t kAccPrivate = 0x0002; // field, method, ic
-static const uint32_t kAccProtected = 0x0004; // field, method, ic
-static const uint32_t kAccStatic = 0x0008; // field, method, ic
-static const uint32_t kAccFinal = 0x0010; // class, field, method, ic
-static const uint32_t kAccSynchronized = 0x0020; // method (only allowed on natives)
-static const uint32_t kAccSuper = 0x0020; // class (not used in dex)
-static const uint32_t kAccVolatile = 0x0040; // field
-static const uint32_t kAccBridge = 0x0040; // method (1.5)
-static const uint32_t kAccTransient = 0x0080; // field
-static const uint32_t kAccVarargs = 0x0080; // method (1.5)
-static const uint32_t kAccNative = 0x0100; // method
-static const uint32_t kAccInterface = 0x0200; // class, ic
-static const uint32_t kAccAbstract = 0x0400; // class, method, ic
-static const uint32_t kAccStrict = 0x0800; // method
-static const uint32_t kAccSynthetic = 0x1000; // class, field, method, ic
-static const uint32_t kAccAnnotation = 0x2000; // class, ic (1.5)
-static const uint32_t kAccEnum = 0x4000; // class, field, ic (1.5)
+static constexpr uint32_t kAccPublic = 0x0001; // class, field, method, ic
+static constexpr uint32_t kAccPrivate = 0x0002; // field, method, ic
+static constexpr uint32_t kAccProtected = 0x0004; // field, method, ic
+static constexpr uint32_t kAccStatic = 0x0008; // field, method, ic
+static constexpr uint32_t kAccFinal = 0x0010; // class, field, method, ic
+static constexpr uint32_t kAccSynchronized = 0x0020; // method (only allowed on natives)
+static constexpr uint32_t kAccSuper = 0x0020; // class (not used in dex)
+static constexpr uint32_t kAccVolatile = 0x0040; // field
+static constexpr uint32_t kAccBridge = 0x0040; // method (1.5)
+static constexpr uint32_t kAccTransient = 0x0080; // field
+static constexpr uint32_t kAccVarargs = 0x0080; // method (1.5)
+static constexpr uint32_t kAccNative = 0x0100; // method
+static constexpr uint32_t kAccInterface = 0x0200; // class, ic
+static constexpr uint32_t kAccAbstract = 0x0400; // class, method, ic
+static constexpr uint32_t kAccStrict = 0x0800; // method
+static constexpr uint32_t kAccSynthetic = 0x1000; // class, field, method, ic
+static constexpr uint32_t kAccAnnotation = 0x2000; // class, ic (1.5)
+static constexpr uint32_t kAccEnum = 0x4000; // class, field, ic (1.5)
-static const uint32_t kAccMiranda = 0x8000; // method
+static constexpr uint32_t kAccJavaFlagsMask = 0xffff; // bits set from Java sources (low 16)
-static const uint32_t kAccJavaFlagsMask = 0xffff; // bits set from Java sources (low 16)
-
-static const uint32_t kAccConstructor = 0x00010000; // method (dex only) <init> and <clinit>
-static const uint32_t kAccDeclaredSynchronized = 0x00020000; // method (dex only)
-static const uint32_t kAccClassIsProxy = 0x00040000; // class (dex only)
-static const uint32_t kAccPreverified = 0x00080000; // class (runtime), method (dex only)
-static const uint32_t kAccFastNative = 0x0080000; // method (dex only)
-static const uint32_t kAccPortableCompiled = 0x0100000; // method (dex only)
+static constexpr uint32_t kAccConstructor = 0x00010000; // method (dex only) <(cl)init>
+static constexpr uint32_t kAccDeclaredSynchronized = 0x00020000; // method (dex only)
+static constexpr uint32_t kAccClassIsProxy = 0x00040000; // class (dex only)
+static constexpr uint32_t kAccPreverified = 0x00080000; // class (runtime),
+ // method (dex only)
+static constexpr uint32_t kAccFastNative = 0x00080000; // method (dex only)
+static constexpr uint32_t kAccPortableCompiled = 0x00100000; // method (dex only)
+static constexpr uint32_t kAccMiranda = 0x00200000; // method (dex only)
// Special runtime-only flags.
// Note: if only kAccClassIsReference is set, we have a soft reference.
-static const uint32_t kAccClassIsFinalizable = 0x80000000; // class/ancestor overrides finalize()
-static const uint32_t kAccClassIsReference = 0x08000000; // class is a soft/weak/phantom ref
-static const uint32_t kAccClassIsWeakReference = 0x04000000; // class is a weak reference
-static const uint32_t kAccClassIsFinalizerReference = 0x02000000; // class is a finalizer reference
-static const uint32_t kAccClassIsPhantomReference = 0x01000000; // class is a phantom reference
-static const uint32_t kAccReferenceFlagsMask = (kAccClassIsReference
- | kAccClassIsWeakReference
- | kAccClassIsFinalizerReference
- | kAccClassIsPhantomReference);
+// class/ancestor overrides finalize()
+static constexpr uint32_t kAccClassIsFinalizable = 0x80000000;
+// class is a soft/weak/phantom ref
+static constexpr uint32_t kAccClassIsReference = 0x08000000;
+// class is a weak reference
+static constexpr uint32_t kAccClassIsWeakReference = 0x04000000;
+// class is a finalizer reference
+static constexpr uint32_t kAccClassIsFinalizerReference = 0x02000000;
+// class is a phantom reference
+static constexpr uint32_t kAccClassIsPhantomReference = 0x01000000;
+
+static constexpr uint32_t kAccReferenceFlagsMask = (kAccClassIsReference
+ | kAccClassIsWeakReference
+ | kAccClassIsFinalizerReference
+ | kAccClassIsPhantomReference);
+
+// Valid (meaningful) bits for a field.
+static constexpr uint32_t kAccValidFieldFlags = kAccPublic | kAccPrivate | kAccProtected |
+ kAccStatic | kAccFinal | kAccVolatile | kAccTransient | kAccSynthetic | kAccEnum;
+
+// Valid (meaningful) bits for a method.
+static constexpr uint32_t kAccValidMethodFlags = kAccPublic | kAccPrivate | kAccProtected |
+ kAccStatic | kAccFinal | kAccSynchronized | kAccBridge | kAccVarargs | kAccNative |
+ kAccAbstract | kAccStrict | kAccSynthetic | kAccMiranda | kAccConstructor |
+ kAccDeclaredSynchronized;
+
+// Valid (meaningful) bits for a class (not interface).
+// Note 1. These are positive bits. Other bits may have to be zero.
+// Note 2. Inner classes can expose more access flags to Java programs. That is handled by libcore.
+static constexpr uint32_t kAccValidClassFlags = kAccPublic | kAccFinal | kAccSuper |
+ kAccAbstract | kAccSynthetic | kAccEnum;
+
+// Valid (meaningful) bits for an interface.
+// Note 1. Annotations are interfaces.
+// Note 2. These are positive bits. Other bits may have to be zero.
+// Note 3. Inner classes can expose more access flags to Java programs. That is handled by libcore.
+static constexpr uint32_t kAccValidInterfaceFlags = kAccPublic | kAccInterface |
+ kAccAbstract | kAccSynthetic | kAccAnnotation;
#endif // ART_RUNTIME_MODIFIERS_H_
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index b799588bce..0de1e76c6f 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -175,7 +175,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(Thread* self,
class_def,
it.GetMethodCodeItem(),
h_method,
- it.GetMemberAccessFlags(),
+ it.GetMethodAccessFlags(),
allow_soft_failures,
false);
if (result != kNoFailure) {
@@ -223,7 +223,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(Thread* self,
class_def,
it.GetMethodCodeItem(),
h_method,
- it.GetMemberAccessFlags(),
+ it.GetMethodAccessFlags(),
allow_soft_failures,
false);
if (result != kNoFailure) {
diff --git a/test/121-modifiers/build b/test/121-modifiers/build
new file mode 100644
index 0000000000..d73be86f95
--- /dev/null
+++ b/test/121-modifiers/build
@@ -0,0 +1,34 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Stop if something fails.
+set -e
+
+# The classes are pre-compiled and modified with ASM.
+#
+# To reproduce, compile the source files. Asm.java needs the ASM libraries (core and tree). Then
+# run Asm.java, which produces Inf.out and NonInf.out. Rename these to class files and put them
+# into the classes directory (this assumes the ASM libraries are names asm.jar and asm-tree.jar):
+#
+# javac Inf.java NonInf.java Main.java
+# javac -cp asm.jar:asm-tree.jar:. Asm.java
+# java -cp asm.jar:asm-tree.jar:. Asm
+# mv Inf.out classes/Inf.class
+# mv NonInf.out classes/NonInf.class
+# mv Main.class A.class A\$B.class A\$C.class classes/
+
+${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+zip $TEST_NAME.jar classes.dex
diff --git a/test/121-modifiers/classes/A$B.class b/test/121-modifiers/classes/A$B.class
new file mode 100644
index 0000000000..bd7ebfe11d
--- /dev/null
+++ b/test/121-modifiers/classes/A$B.class
Binary files differ
diff --git a/test/121-modifiers/classes/A$C.class b/test/121-modifiers/classes/A$C.class
new file mode 100644
index 0000000000..3ae872e356
--- /dev/null
+++ b/test/121-modifiers/classes/A$C.class
Binary files differ
diff --git a/test/121-modifiers/classes/A.class b/test/121-modifiers/classes/A.class
new file mode 100644
index 0000000000..d89d029796
--- /dev/null
+++ b/test/121-modifiers/classes/A.class
Binary files differ
diff --git a/test/121-modifiers/classes/Inf.class b/test/121-modifiers/classes/Inf.class
new file mode 100644
index 0000000000..e8dd68029d
--- /dev/null
+++ b/test/121-modifiers/classes/Inf.class
Binary files differ
diff --git a/test/121-modifiers/classes/Main.class b/test/121-modifiers/classes/Main.class
new file mode 100644
index 0000000000..e044074269
--- /dev/null
+++ b/test/121-modifiers/classes/Main.class
Binary files differ
diff --git a/test/121-modifiers/classes/NonInf.class b/test/121-modifiers/classes/NonInf.class
new file mode 100644
index 0000000000..0f1e826fb7
--- /dev/null
+++ b/test/121-modifiers/classes/NonInf.class
Binary files differ
diff --git a/test/121-modifiers/expected.txt b/test/121-modifiers/expected.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/121-modifiers/expected.txt
diff --git a/test/121-modifiers/info.txt b/test/121-modifiers/info.txt
new file mode 100644
index 0000000000..943cbf8aba
--- /dev/null
+++ b/test/121-modifiers/info.txt
@@ -0,0 +1 @@
+This is a test checking the modifier (access flags) handling of ART.
diff --git a/test/121-modifiers/src/Asm.java b/test/121-modifiers/src/Asm.java
new file mode 100644
index 0000000000..f120622120
--- /dev/null
+++ b/test/121-modifiers/src/Asm.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.objectweb.asm.*;
+import org.objectweb.asm.tree.*;
+import java.io.*;
+import java.util.*;
+
+public class Asm {
+ /*
+
+ Overall class access flags:
+
+ 0x0001 | // public
+ 0x0010 | // final
+ 0x0020 | // super
+ 0x0200 | // interface
+ 0x0400 | // abstract
+ 0x1000 | // synthetic
+ 0x2000 | // annotation
+ 0x4000 ; // enum
+
+ */
+
+ public final static int INTERFACE_DEFINED_BITS =
+ 0x0001 | // public, may be set.
+ 0x0010 | // final, must not be set.
+ 0x0020 | // super, must not be set.
+ 0x0200 | // interface, must be set.
+ 0x0400 | // abstract, must be set.
+ 0x1000 | // synthetic, may be set.
+ 0x2000 | // annotation, may be set (annotation implies interface)
+ 0x4000 ; // enum, must not be set.
+
+ public final static int CLASS_DEFINED_BITS =
+ 0x0001 | // public, may be set.
+ 0x0010 | // final, may be set.
+ 0x0020 | // super, may be set.
+ 0x0200 | // interface, must not be set.
+ 0x0400 | // abstract, may be set.
+ 0x1000 | // synthetic, may be set.
+ 0x2000 | // annotation, must not be set.
+ 0x4000 ; // enum, may be set.
+
+ public final static int FIELD_DEFINED_BITS =
+ 0x0001 | // public
+ 0x0002 | // private
+ 0x0004 | // protected
+ 0x0008 | // static
+ 0x0010 | // final
+ 0x0040 | // volatile
+ 0x0080 | // transient
+ 0x1000 | // synthetic
+ 0x4000 ; // enum
+
+ public final static int METHOD_DEFINED_BITS =
+ 0x0001 | // public
+ 0x0002 | // private
+ 0x0004 | // protected
+ 0x0008 | // static
+ 0x0010 | // final
+ 0x0020 | // synchronized
+ 0x0040 | // bridge
+ 0x0080 | // varargs
+ 0x0100 | // native
+ 0x0400 | // abstract
+ 0x0800 | // strictfp
+ 0x1000 ; // synthetic
+
+ public static void main(String args[]) throws Exception {
+ modify("Inf");
+ modify("NonInf");
+ }
+
+ private static void modify(String clazz) throws Exception {
+ ClassNode classNode = new ClassNode();
+ ClassReader cr = new ClassReader(clazz);
+ cr.accept(classNode, 0);
+
+ modify(classNode);
+
+ ClassWriter cw = new ClassWriter(0);
+ classNode.accept(cw);
+ byte[] b = cw.toByteArray();
+ OutputStream out = new FileOutputStream(clazz + ".out");
+ out.write(b, 0, b.length);
+ out.close();
+ }
+
+ private static void modify(ClassNode classNode) throws Exception {
+ int classFlagsOr = 0xFFFF;
+ // Check whether classNode is an interface or class.
+ if ((classNode.access & Opcodes.ACC_INTERFACE) == 0) {
+ classFlagsOr ^= CLASS_DEFINED_BITS;
+ } else {
+ classFlagsOr ^= INTERFACE_DEFINED_BITS;
+ }
+ classNode.access |= classFlagsOr;
+
+ // Fields.
+ int fieldFlagsOr = 0xFFFF ^ FIELD_DEFINED_BITS;
+ for (FieldNode fieldNode : (List<FieldNode>)classNode.fields) {
+ fieldNode.access |= fieldFlagsOr;
+ }
+
+ // Methods.
+ int methodFlagsOr = 0xFFFF ^ METHOD_DEFINED_BITS;
+ for (MethodNode methodNode :(List<MethodNode>) classNode.methods) {
+ methodNode.access |= methodFlagsOr;
+ }
+ }
+}
diff --git a/test/121-modifiers/src/Inf.java b/test/121-modifiers/src/Inf.java
new file mode 100644
index 0000000000..1dadae0e47
--- /dev/null
+++ b/test/121-modifiers/src/Inf.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public interface Inf {
+
+ public final int I = 0;
+
+} \ No newline at end of file
diff --git a/test/121-modifiers/src/Main.java b/test/121-modifiers/src/Main.java
new file mode 100644
index 0000000000..e21b789cc7
--- /dev/null
+++ b/test/121-modifiers/src/Main.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// These classes are to check the additional flags for inner classes.
+class A {
+ private static class B {
+ }
+ protected static interface C {
+ }
+}
+
+public class Main {
+ public final static int INTERFACE_DEFINED_BITS =
+ 0x0001 | // public, may be set.
+ 0x0002 | // private, may be flagged by inner class.
+ 0x0004 | // protected, may be flagged by inner class.
+ 0x0008 | // static, may be flagged by inner class.
+ 0x0010 | // final, must not be set.
+ 0x0020 | // super, must not be set.
+ 0x0200 | // interface, must be set.
+ 0x0400 | // abstract, must be set.
+ 0x1000 | // synthetic, may be set.
+ 0x2000 | // annotation, may be set (annotation implies interface)
+ 0x4000 ; // enum, must not be set.
+
+ public final static int CLASS_DEFINED_BITS =
+ 0x0001 | // public, may be set.
+ 0x0002 | // private, may be flagged by inner class.
+ 0x0004 | // protected, may be flagged by inner class.
+ 0x0008 | // static, may be flagged by inner class.
+ 0x0010 | // final, may be set.
+ 0x0020 | // super, may be set.
+ 0x0200 | // interface, must not be set.
+ 0x0400 | // abstract, may be set.
+ 0x1000 | // synthetic, may be set.
+ 0x2000 | // annotation, must not be set.
+ 0x4000 ; // enum, may be set.
+
+ public final static int FIELD_DEFINED_BITS =
+ 0x0001 | // public
+ 0x0002 | // private
+ 0x0004 | // protected
+ 0x0008 | // static
+ 0x0010 | // final
+ 0x0040 | // volatile
+ 0x0080 | // transient
+ 0x1000 | // synthetic
+ 0x4000 ; // enum
+
+ public final static int METHOD_DEFINED_BITS =
+ 0x0001 | // public
+ 0x0002 | // private
+ 0x0004 | // protected
+ 0x0008 | // static
+ 0x0010 | // final
+ 0x0020 | // synchronized
+ 0x0040 | // bridge
+ 0x0080 | // varargs
+ 0x0100 | // native
+ 0x0400 | // abstract
+ 0x0800 | // strictfp
+ 0x1000 ; // synthetic
+
+ public static void main(String args[]) throws Exception {
+ check("Inf");
+ check("NonInf");
+ check("A");
+ check("A$B");
+ }
+
+ private static void check(String className) throws Exception {
+ Class<?> clazz = Class.forName(className);
+ if (className.equals("Inf")) {
+ if (!clazz.isInterface()) {
+ throw new RuntimeException("Expected an interface.");
+ }
+ int undefinedBits = 0xFFFF ^ INTERFACE_DEFINED_BITS;
+ if ((clazz.getModifiers() & undefinedBits) != 0) {
+ System.out.println("Clazz.getModifiers(): " + Integer.toBinaryString(clazz.getModifiers()));
+ System.out.println("INTERFACE_DEF_BITS: " + Integer.toBinaryString(INTERFACE_DEFINED_BITS));
+ throw new RuntimeException("Undefined bits for an interface: " + className);
+ }
+ } else {
+ if (clazz.isInterface()) {
+ throw new RuntimeException("Expected a class.");
+ }
+ int undefinedBits = 0xFFFF ^ CLASS_DEFINED_BITS;
+ if ((clazz.getModifiers() & undefinedBits) != 0) {
+ System.out.println("Clazz.getModifiers(): " + Integer.toBinaryString(clazz.getModifiers()));
+ System.out.println("CLASS_DEF_BITS: " + Integer.toBinaryString(CLASS_DEFINED_BITS));
+ throw new RuntimeException("Undefined bits for a class: " + className);
+ }
+ }
+
+ // Check fields.
+ for (java.lang.reflect.Field f : clazz.getDeclaredFields()) {
+ String name = f.getName();
+ int undefinedBits = 0xFFFF ^ FIELD_DEFINED_BITS;
+ if ((f.getModifiers() & undefinedBits) != 0) {
+ System.out.println("f.getModifiers(): " + Integer.toBinaryString(f.getModifiers()));
+ System.out.println("FIELD_DEF_BITS: " + Integer.toBinaryString(FIELD_DEFINED_BITS));
+ throw new RuntimeException("Unexpected field bits: " + name);
+ }
+ if (name.equals("I")) {
+ // Interface field, just check generically.
+ } else {
+ // Check the name, see that the corresponding bit is set.
+ int bitmask = getFieldMask(name);
+ if ((bitmask & f.getModifiers()) == 0) {
+ throw new RuntimeException("Expected field bit not set.");
+ }
+ }
+ }
+
+ // Check methods.
+ for (java.lang.reflect.Method m : clazz.getDeclaredMethods()) {
+ String name = m.getName();
+ int undefinedBits = 0xFFFF ^ METHOD_DEFINED_BITS;
+ if ((m.getModifiers() & undefinedBits) != 0) {
+ System.out.println("m.getModifiers(): " + Integer.toBinaryString(m.getModifiers()));
+ System.out.println("METHOD_DEF_BITS: " + Integer.toBinaryString(METHOD_DEFINED_BITS));
+ throw new RuntimeException("Unexpected method bits: " + name);
+ }
+ // Check the name, see that the corresponding bit is set.
+ int bitmask = getMethodMask(name);
+ if ((bitmask & m.getModifiers()) == 0) {
+ throw new RuntimeException("Expected method bit not set.");
+ }
+ }
+ }
+
+ private static int getFieldMask(String name) {
+ int index = name.indexOf("Field");
+ if (index > 0) {
+ String shortS = name.substring(0, index);
+ if (shortS.equals("public")) {
+ return 0x0001;
+ }
+ if (shortS.equals("private")) {
+ return 0x0002;
+ }
+ if (shortS.equals("protected")) {
+ return 0x0004;
+ }
+ if (shortS.equals("static")) {
+ return 0x0008;
+ }
+ if (shortS.equals("transient")) {
+ return 0x0080;
+ }
+ if (shortS.equals("volatile")) {
+ return 0x0040;
+ }
+ if (shortS.equals("final")) {
+ return 0x0010;
+ }
+ }
+ throw new RuntimeException("Unexpected field name " + name);
+ }
+
+ private static int getMethodMask(String name) {
+ int index = name.indexOf("Method");
+ if (index > 0) {
+ String shortS = name.substring(0, index);
+ if (shortS.equals("public")) {
+ return 0x0001;
+ }
+ if (shortS.equals("private")) {
+ return 0x0002;
+ }
+ if (shortS.equals("protected")) {
+ return 0x0004;
+ }
+ if (shortS.equals("static")) {
+ return 0x0008;
+ }
+ if (shortS.equals("synchronized")) {
+ return 0x0020;
+ }
+ if (shortS.equals("varargs")) {
+ return 0x0080;
+ }
+ if (shortS.equals("final")) {
+ return 0x0010;
+ }
+ if (shortS.equals("native")) {
+ return 0x0100;
+ }
+ if (shortS.equals("abstract")) {
+ return 0x0400;
+ }
+ if (shortS.equals("strictfp")) {
+ return 0x0800;
+ }
+ }
+ throw new RuntimeException("Unexpected method name " + name);
+ }
+}
diff --git a/test/121-modifiers/src/NonInf.java b/test/121-modifiers/src/NonInf.java
new file mode 100644
index 0000000000..52e4882532
--- /dev/null
+++ b/test/121-modifiers/src/NonInf.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public abstract class NonInf {
+
+ public int publicField;
+ private int privateField;
+ protected int protectedField;
+ static int staticField;
+ transient int transientField;
+ volatile int volatileField;
+ final int finalField;
+
+ public NonInf() {
+ publicField = 0;
+ privateField = 1;
+ protectedField = 2;
+ staticField = 3;
+ transientField = 4;
+ volatileField = 5;
+ finalField = 6;
+ }
+
+ public native void nativeMethod();
+
+ private int privateMethod() {
+ return 0;
+ }
+
+ protected int protectedMethod() {
+ return 0;
+ }
+
+ public int publicMethod() {
+ return 0;
+ }
+
+ public abstract int abstractMethod();
+
+ public synchronized int synchronizedMethod() {
+ return 0;
+ }
+
+ public static int staticMethod() {
+ return 0;
+ }
+
+ public strictfp double strictfpMethod() {
+ return 0.0;
+ }
+
+ public int varargsMethod(Object... args) {
+ return 0;
+ }
+
+ public final int finalMethod() {
+ return 0;
+ }
+} \ No newline at end of file