diff options
author | Andreas Gampe <agampe@google.com> | 2014-08-25 15:05:04 -0700 |
---|---|---|
committer | Andreas Gampe <agampe@google.com> | 2014-09-15 09:37:25 -0700 |
commit | 5182932cf6704b53e957f7b4be021fe505a55e22 (patch) | |
tree | 99ee2bfb5a6f4d27735aeed26a0533c759db733c | |
parent | 56369897d662ea63ea5ed57ae36af0ae0fa1452d (diff) | |
download | art-5182932cf6704b53e957f7b4be021fe505a55e22.tar.gz art-5182932cf6704b53e957f7b4be021fe505a55e22.tar.bz2 art-5182932cf6704b53e957f7b4be021fe505a55e22.zip |
ART: Change access flag behavior in verifier
Note: this moves the miranda modifier to the upper 16 bit.
Bug: 16161620
(cherry picked from commit 7fc8f90b7160e879143be5cfd6ea3df866398884)
Change-Id: I2f591d53b7d1559171e70aaaf22225d94b4882f5
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 Binary files differnew file mode 100644 index 0000000000..bd7ebfe11d --- /dev/null +++ b/test/121-modifiers/classes/A$B.class diff --git a/test/121-modifiers/classes/A$C.class b/test/121-modifiers/classes/A$C.class Binary files differnew file mode 100644 index 0000000000..3ae872e356 --- /dev/null +++ b/test/121-modifiers/classes/A$C.class diff --git a/test/121-modifiers/classes/A.class b/test/121-modifiers/classes/A.class Binary files differnew file mode 100644 index 0000000000..d89d029796 --- /dev/null +++ b/test/121-modifiers/classes/A.class diff --git a/test/121-modifiers/classes/Inf.class b/test/121-modifiers/classes/Inf.class Binary files differnew file mode 100644 index 0000000000..e8dd68029d --- /dev/null +++ b/test/121-modifiers/classes/Inf.class diff --git a/test/121-modifiers/classes/Main.class b/test/121-modifiers/classes/Main.class Binary files differnew file mode 100644 index 0000000000..e044074269 --- /dev/null +++ b/test/121-modifiers/classes/Main.class diff --git a/test/121-modifiers/classes/NonInf.class b/test/121-modifiers/classes/NonInf.class Binary files differnew file mode 100644 index 0000000000..0f1e826fb7 --- /dev/null +++ b/test/121-modifiers/classes/NonInf.class 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 |