Index: third_party/ijar/classfile.cc |
diff --git a/third_party/ijar/classfile.cc b/third_party/ijar/classfile.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..39d24f9dd49686e412ae384f61550b949be6b7b4 |
--- /dev/null |
+++ b/third_party/ijar/classfile.cc |
@@ -0,0 +1,1489 @@ |
+// Copyright 2001,2007 Alan Donovan. All rights reserved. |
+// |
+// Author: Alan Donovan <adonovan@google.com> |
+// |
+// 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. |
+// |
+// classfile.cc -- classfile parsing and stripping. |
+// |
+ |
+// TODO(adonovan) don't pass pointers by reference; this is not |
+// compatible with Google C++ style. |
+ |
+// See README.txt for details. |
+// |
+// For definition of JVM class file format, see: |
+// Java SE 8 Edition: |
+// http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4 |
+ |
+#define __STDC_FORMAT_MACROS 1 |
+#define __STDC_LIMIT_MACROS 1 |
+#include <inttypes.h> // for PRIx32 |
+#include <stddef.h> |
+#include <stdio.h> |
+#include <stdlib.h> |
+#include <string.h> |
+ |
+#include <string> |
+#include <vector> |
+ |
+#include "third_party/ijar/common.h" |
+ |
+namespace devtools_ijar { |
+ |
+// See Table 4.3 in JVM Spec. |
+enum CONSTANT { |
+ CONSTANT_Class = 7, |
+ CONSTANT_FieldRef = 9, |
+ CONSTANT_Methodref = 10, |
+ CONSTANT_Interfacemethodref = 11, |
+ CONSTANT_String = 8, |
+ CONSTANT_Integer = 3, |
+ CONSTANT_Float = 4, |
+ CONSTANT_Long = 5, |
+ CONSTANT_Double = 6, |
+ CONSTANT_NameAndType = 12, |
+ CONSTANT_Utf8 = 1, |
+ CONSTANT_MethodHandle = 15, |
+ CONSTANT_MethodType = 16, |
+ CONSTANT_InvokeDynamic = 18 |
+}; |
+ |
+// See Tables 4.1, 4.4, 4.5 in JVM Spec. |
+enum ACCESS { |
+ ACC_PUBLIC = 0x0001, |
+ ACC_PRIVATE = 0x0002, |
+ ACC_PROTECTED = 0x0004, |
+ ACC_STATIC = 0x0008, |
+ ACC_FINAL = 0x0010, |
+ ACC_SYNCHRONIZED = 0x0020, |
+ ACC_VOLATILE = 0x0040, |
+ ACC_TRANSIENT = 0x0080, |
+ ACC_INTERFACE = 0x0200, |
+ ACC_ABSTRACT = 0x0400 |
+}; |
+ |
+// See Table 4.7.20-A in Java 8 JVM Spec. |
+enum TARGET_TYPE { |
+ // Targets for type parameter declarations (ElementType.TYPE_PARAMETER): |
+ CLASS_TYPE_PARAMETER = 0x00, |
+ METHOD_TYPE_PARAMETER = 0x01, |
+ |
+ // Targets for type uses that may be externally visible in classes and members |
+ // (ElementType.TYPE_USE): |
+ CLASS_EXTENDS = 0x10, |
+ CLASS_TYPE_PARAMETER_BOUND = 0x11, |
+ METHOD_TYPE_PARAMETER_BOUND = 0x12, |
+ FIELD = 0x13, |
+ METHOD_RETURN = 0x14, |
+ METHOD_RECEIVER = 0x15, |
+ METHOD_FORMAL_PARAMETER = 0x16, |
+ THROWS = 0x17, |
+ |
+ // TARGET_TYPE >= 0x40 is reserved for type uses that occur only within code |
+ // blocks. Ijar doesn't need to know about these. |
+}; |
+ |
+struct Constant; |
+ |
+// TODO(adonovan) these globals are unfortunate |
+static std::vector<Constant*> const_pool_in; // input constant pool |
+static std::vector<Constant*> const_pool_out; // output constant_pool |
+ |
+// Returns the Constant object, given an index into the input constant pool. |
+// Note: constant(0) == NULL; this invariant is exploited by the |
+// InnerClassesAttribute, inter alia. |
+inline Constant *constant(int idx) { |
+ if (idx < 0 || (unsigned)idx >= const_pool_in.size()) { |
+ fprintf(stderr, "Illegal constant pool index: %d\n", idx); |
+ abort(); |
+ } |
+ return const_pool_in[idx]; |
+} |
+ |
+/********************************************************************** |
+ * * |
+ * Constants * |
+ * * |
+ **********************************************************************/ |
+ |
+// See sec.4.4 of JVM spec. |
+struct Constant { |
+ |
+ Constant(u1 tag) : |
+ slot_(0), |
+ tag_(tag) {} |
+ |
+ virtual ~Constant() {} |
+ |
+ // For UTF-8 string constants, returns the encoded string. |
+ // Otherwise, returns an undefined string value suitable for debugging. |
+ virtual std::string Display() = 0; |
+ |
+ virtual void Write(u1 *&p) = 0; |
+ |
+ // Called by slot() when a constant has been identified as required |
+ // in the output classfile's constant pool. This is a hook allowing |
+ // constants to register their dependency on other constants, by |
+ // calling slot() on them in turn. |
+ virtual void Keep() {} |
+ |
+ // Returns the index of this constant in the output class's constant |
+ // pool, assigning a slot if not already done. |
+ u2 slot() { |
+ if (slot_ == 0) { |
+ Keep(); |
+ slot_ = const_pool_out.size(); // BugBot's "narrowing" warning |
+ // is bogus. The number of |
+ // output constants can't exceed |
+ // the number of input constants. |
+ if (slot_ == 0) { |
+ fprintf(stderr, "Constant::slot() called before output phase.\n"); |
+ abort(); |
+ } |
+ const_pool_out.push_back(this); |
+ if (tag_ == CONSTANT_Long || tag_ == CONSTANT_Double) { |
+ const_pool_out.push_back(NULL); |
+ } |
+ } |
+ return slot_; |
+ } |
+ |
+ u2 slot_; // zero => "this constant is unreachable garbage" |
+ u1 tag_; |
+}; |
+ |
+// See sec.4.4.1 of JVM spec. |
+struct Constant_Class : Constant |
+{ |
+ Constant_Class(u2 name_index) : |
+ Constant(CONSTANT_Class), |
+ name_index_(name_index) {} |
+ |
+ void Write(u1 *&p) { |
+ put_u1(p, tag_); |
+ put_u2be(p, constant(name_index_)->slot()); |
+ } |
+ |
+ std::string Display() { |
+ return constant(name_index_)->Display(); |
+ } |
+ |
+ void Keep() { constant(name_index_)->slot(); } |
+ |
+ u2 name_index_; |
+}; |
+ |
+// See sec.4.4.2 of JVM spec. |
+struct Constant_FMIref : Constant |
+{ |
+ Constant_FMIref(u1 tag, |
+ u2 class_index, |
+ u2 name_type_index) : |
+ Constant(tag), |
+ class_index_(class_index), |
+ name_type_index_(name_type_index) {} |
+ |
+ void Write(u1 *&p) { |
+ put_u1(p, tag_); |
+ put_u2be(p, constant(class_index_)->slot()); |
+ put_u2be(p, constant(name_type_index_)->slot()); |
+ } |
+ |
+ std::string Display() { |
+ return constant(class_index_)->Display() + "::" + |
+ constant(name_type_index_)->Display(); |
+ } |
+ |
+ void Keep() { |
+ constant(class_index_)->slot(); |
+ constant(name_type_index_)->slot(); |
+ } |
+ |
+ u2 class_index_; |
+ u2 name_type_index_; |
+}; |
+ |
+// See sec.4.4.3 of JVM spec. |
+struct Constant_String : Constant |
+{ |
+ Constant_String(u2 string_index) : |
+ Constant(CONSTANT_String), |
+ string_index_(string_index) {} |
+ |
+ void Write(u1 *&p) { |
+ put_u1(p, tag_); |
+ put_u2be(p, constant(string_index_)->slot()); |
+ } |
+ |
+ std::string Display() { |
+ return "\"" + constant(string_index_)->Display() + "\""; |
+ } |
+ |
+ void Keep() { constant(string_index_)->slot(); } |
+ |
+ u2 string_index_; |
+}; |
+ |
+// See sec.4.4.4 of JVM spec. |
+struct Constant_IntegerOrFloat : Constant |
+{ |
+ Constant_IntegerOrFloat(u1 tag, u4 bytes) : |
+ Constant(tag), |
+ bytes_(bytes) {} |
+ |
+ void Write(u1 *&p) { |
+ put_u1(p, tag_); |
+ put_u4be(p, bytes_); |
+ } |
+ |
+ std::string Display() { return "int/float"; } |
+ |
+ u4 bytes_; |
+}; |
+ |
+// See sec.4.4.5 of JVM spec. |
+struct Constant_LongOrDouble : Constant_IntegerOrFloat |
+{ |
+ Constant_LongOrDouble(u1 tag, u4 high_bytes, u4 low_bytes) : |
+ Constant_IntegerOrFloat(tag, high_bytes), |
+ low_bytes_(low_bytes) {} |
+ |
+ void Write(u1 *&p) { |
+ put_u1(p, tag_); |
+ put_u4be(p, bytes_); |
+ put_u4be(p, low_bytes_); |
+ } |
+ |
+ std::string Display() { return "long/double"; } |
+ |
+ u4 low_bytes_; |
+}; |
+ |
+// See sec.4.4.6 of JVM spec. |
+struct Constant_NameAndType : Constant |
+{ |
+ Constant_NameAndType(u2 name_index, u2 descr_index) : |
+ Constant(CONSTANT_NameAndType), |
+ name_index_(name_index), |
+ descr_index_(descr_index) {} |
+ |
+ void Write(u1 *&p) { |
+ put_u1(p, tag_); |
+ put_u2be(p, constant(name_index_)->slot()); |
+ put_u2be(p, constant(descr_index_)->slot()); |
+ } |
+ |
+ std::string Display() { |
+ return constant(name_index_)->Display() + "::" + |
+ constant(descr_index_)->Display(); |
+ } |
+ |
+ void Keep() { |
+ constant(name_index_)->slot(); |
+ constant(descr_index_)->slot(); |
+ } |
+ |
+ u2 name_index_; |
+ u2 descr_index_; |
+}; |
+ |
+// See sec.4.4.7 of JVM spec. |
+struct Constant_Utf8 : Constant |
+{ |
+ Constant_Utf8(u4 length, const u1 *utf8) : |
+ Constant(CONSTANT_Utf8), |
+ length_(length), |
+ utf8_(utf8) {} |
+ |
+ void Write(u1 *&p) { |
+ put_u1(p, tag_); |
+ put_u2be(p, length_); |
+ put_n(p, utf8_, length_); |
+ } |
+ |
+ std::string Display() { |
+ return std::string((const char*) utf8_, length_); |
+ } |
+ |
+ u4 length_; |
+ const u1 *utf8_; |
+}; |
+ |
+// See sec.4.4.8 of JVM spec. |
+struct Constant_MethodHandle : Constant |
+{ |
+ Constant_MethodHandle(u1 reference_kind, u2 reference_index) : |
+ Constant(CONSTANT_MethodHandle), |
+ reference_kind_(reference_kind), |
+ reference_index_(reference_index) {} |
+ |
+ void Write(u1 *&p) { |
+ put_u1(p, tag_); |
+ put_u1(p, reference_kind_); |
+ put_u2be(p, reference_index_); |
+ } |
+ |
+ std::string Display() { |
+ return "Constant_MethodHandle::" + std::to_string(reference_kind_) + "::" |
+ + constant(reference_index_)->Display(); |
+ } |
+ |
+ u1 reference_kind_; |
+ u2 reference_index_; |
+}; |
+ |
+// See sec.4.4.9 of JVM spec. |
+struct Constant_MethodType : Constant |
+{ |
+ Constant_MethodType(u2 descriptor_index) : |
+ Constant(CONSTANT_MethodType), |
+ descriptor_index_(descriptor_index) {} |
+ |
+ void Write(u1 *&p) { |
+ put_u1(p, tag_); |
+ put_u2be(p, descriptor_index_); |
+ } |
+ |
+ std::string Display() { |
+ return "Constant_MethodType::" + constant(descriptor_index_)->Display(); |
+ } |
+ |
+ u2 descriptor_index_; |
+}; |
+ |
+// See sec.4.4.10 of JVM spec. |
+struct Constant_InvokeDynamic : Constant |
+{ |
+ Constant_InvokeDynamic(u2 bootstrap_method_attr_index, u2 name_and_type_index) : |
+ Constant(CONSTANT_InvokeDynamic), |
+ bootstrap_method_attr_index_(bootstrap_method_attr_index), |
+ name_and_type_index_(name_and_type_index) {} |
+ |
+ void Write(u1 *&p) { |
+ put_u1(p, tag_); |
+ put_u2be(p, bootstrap_method_attr_index_); |
+ put_u2be(p, name_and_type_index_); |
+ } |
+ |
+ std::string Display() { |
+ return "Constant_InvokeDynamic::" |
+ + std::to_string(bootstrap_method_attr_index_) + "::" |
+ + constant(name_and_type_index_)->Display(); |
+ } |
+ |
+ u2 bootstrap_method_attr_index_; |
+ u2 name_and_type_index_; |
+}; |
+ |
+/********************************************************************** |
+ * * |
+ * Attributes * |
+ * * |
+ **********************************************************************/ |
+ |
+// See sec.4.7 of JVM spec. |
+struct Attribute { |
+ |
+ virtual ~Attribute() {} |
+ virtual void Write(u1 *&p) = 0; |
+ |
+ void WriteProlog(u1 *&p, u2 length) { |
+ put_u2be(p, attribute_name_->slot()); |
+ put_u4be(p, length); |
+ } |
+ |
+ Constant *attribute_name_; |
+}; |
+ |
+// See sec.4.7.5 of JVM spec. |
+struct ExceptionsAttribute : Attribute { |
+ |
+ static ExceptionsAttribute* Read(const u1 *&p, Constant *attribute_name) { |
+ ExceptionsAttribute *attr = new ExceptionsAttribute; |
+ attr->attribute_name_ = attribute_name; |
+ u2 number_of_exceptions = get_u2be(p); |
+ for (int ii = 0; ii < number_of_exceptions; ++ii) { |
+ attr->exceptions_.push_back(constant(get_u2be(p))); |
+ } |
+ return attr; |
+ } |
+ |
+ void Write(u1 *&p) { |
+ WriteProlog(p, exceptions_.size() * 2 + 2); |
+ put_u2be(p, exceptions_.size()); |
+ for (size_t ii = 0; ii < exceptions_.size(); ++ii) { |
+ put_u2be(p, exceptions_[ii]->slot()); |
+ } |
+ } |
+ |
+ std::vector<Constant*> exceptions_; |
+}; |
+ |
+// See sec.4.7.6 of JVM spec. |
+struct InnerClassesAttribute : Attribute { |
+ |
+ struct Entry { |
+ Constant *inner_class_info; |
+ Constant *outer_class_info; |
+ Constant *inner_name; |
+ u2 inner_class_access_flags; |
+ }; |
+ |
+ virtual ~InnerClassesAttribute() { |
+ for (size_t i = 0; i < entries_.size(); i++) { |
+ delete entries_[i]; |
+ } |
+ } |
+ |
+ static InnerClassesAttribute* Read(const u1 *&p, Constant *attribute_name) { |
+ InnerClassesAttribute *attr = new InnerClassesAttribute; |
+ attr->attribute_name_ = attribute_name; |
+ |
+ u2 number_of_classes = get_u2be(p); |
+ for (int ii = 0; ii < number_of_classes; ++ii) { |
+ Entry *entry = new Entry; |
+ entry->inner_class_info = constant(get_u2be(p)); |
+ entry->outer_class_info = constant(get_u2be(p)); |
+ entry->inner_name = constant(get_u2be(p)); |
+ entry->inner_class_access_flags = get_u2be(p); |
+ |
+ attr->entries_.push_back(entry); |
+ } |
+ return attr; |
+ } |
+ |
+ void Write(u1 *&p) { |
+ WriteProlog(p, 2 + entries_.size() * 8); |
+ put_u2be(p, entries_.size()); |
+ for (size_t ii = 0; ii < entries_.size(); ++ii) { |
+ Entry *entry = entries_[ii]; |
+ put_u2be(p, entry->inner_class_info == NULL |
+ ? 0 |
+ : entry->inner_class_info->slot()); |
+ put_u2be(p, entry->outer_class_info == NULL |
+ ? 0 |
+ : entry->outer_class_info->slot()); |
+ put_u2be(p, entry->inner_name == NULL |
+ ? 0 |
+ : entry->inner_name->slot()); |
+ put_u2be(p, entry->inner_class_access_flags); |
+ } |
+ } |
+ |
+ std::vector<Entry*> entries_; |
+}; |
+ |
+// See sec.4.7.7 of JVM spec. |
+// We preserve EnclosingMethod attributes to be able to identify local and |
+// anonymous classes. These classes will be stripped of most content, as they |
+// represent implementation details that shoudn't leak into the ijars. Omitting |
+// EnclosingMethod attributes can lead to type-checking failures in the presence |
+// of generics (see b/9070939). |
+struct EnclosingMethodAttribute : Attribute { |
+ |
+ static EnclosingMethodAttribute* Read(const u1 *&p, |
+ Constant *attribute_name) { |
+ EnclosingMethodAttribute *attr = new EnclosingMethodAttribute; |
+ attr->attribute_name_ = attribute_name; |
+ attr->class_ = constant(get_u2be(p)); |
+ attr->method_ = constant(get_u2be(p)); |
+ return attr; |
+ } |
+ |
+ void Write(u1 *&p) { |
+ WriteProlog(p, 4); |
+ put_u2be(p, class_->slot()); |
+ put_u2be(p, method_ == NULL ? 0 : method_->slot()); |
+ } |
+ |
+ Constant *class_; |
+ Constant *method_; |
+}; |
+ |
+// See sec.4.7.16.1 of JVM spec. |
+// Used by AnnotationDefault and other attributes. |
+struct ElementValue { |
+ virtual ~ElementValue() {} |
+ virtual void Write(u1 *&p) = 0; |
+ static ElementValue* Read(const u1 *&p); |
+ u1 tag_; |
+ u4 length_; |
+}; |
+ |
+struct BaseTypeElementValue : ElementValue { |
+ void Write(u1 *&p) { |
+ put_u1(p, tag_); |
+ put_u2be(p, const_value_->slot()); |
+ } |
+ static BaseTypeElementValue *Read(const u1 *&p) { |
+ BaseTypeElementValue *value = new BaseTypeElementValue; |
+ value->const_value_ = constant(get_u2be(p)); |
+ return value; |
+ } |
+ Constant *const_value_; |
+}; |
+ |
+struct EnumTypeElementValue : ElementValue { |
+ void Write(u1 *&p) { |
+ put_u1(p, tag_); |
+ put_u2be(p, type_name_->slot()); |
+ put_u2be(p, const_name_->slot()); |
+ } |
+ static EnumTypeElementValue *Read(const u1 *&p) { |
+ EnumTypeElementValue *value = new EnumTypeElementValue; |
+ value->type_name_ = constant(get_u2be(p)); |
+ value->const_name_ = constant(get_u2be(p)); |
+ return value; |
+ } |
+ Constant *type_name_; |
+ Constant *const_name_; |
+}; |
+ |
+struct ClassTypeElementValue : ElementValue { |
+ void Write(u1 *&p) { |
+ put_u1(p, tag_); |
+ put_u2be(p, class_info_->slot()); |
+ } |
+ static ClassTypeElementValue *Read(const u1 *&p) { |
+ ClassTypeElementValue *value = new ClassTypeElementValue; |
+ value->class_info_ = constant(get_u2be(p)); |
+ return value; |
+ } |
+ Constant *class_info_; |
+}; |
+ |
+struct ArrayTypeElementValue : ElementValue { |
+ virtual ~ArrayTypeElementValue() { |
+ for (size_t i = 0; i < values_.size(); i++) { |
+ delete values_[i]; |
+ } |
+ } |
+ |
+ void Write(u1 *&p) { |
+ put_u1(p, tag_); |
+ put_u2be(p, values_.size()); |
+ for (size_t ii = 0; ii < values_.size(); ++ii) { |
+ values_[ii]->Write(p); |
+ } |
+ } |
+ static ArrayTypeElementValue *Read(const u1 *&p) { |
+ ArrayTypeElementValue *value = new ArrayTypeElementValue; |
+ u2 num_values = get_u2be(p); |
+ for (int ii = 0; ii < num_values; ++ii) { |
+ value->values_.push_back(ElementValue::Read(p)); |
+ } |
+ return value; |
+ } |
+ std::vector<ElementValue*> values_; |
+}; |
+ |
+// See sec.4.7.16 of JVM spec. |
+struct Annotation { |
+ virtual ~Annotation() { |
+ for (size_t i = 0; i < element_value_pairs_.size(); i++) { |
+ delete element_value_pairs_[i]->element_value_; |
+ delete element_value_pairs_[i]; |
+ } |
+ } |
+ |
+ void Write(u1 *&p) { |
+ put_u2be(p, type_->slot()); |
+ put_u2be(p, element_value_pairs_.size()); |
+ for (size_t ii = 0; ii < element_value_pairs_.size(); ++ii) { |
+ put_u2be(p, element_value_pairs_[ii]->element_name_->slot()); |
+ element_value_pairs_[ii]->element_value_->Write(p); |
+ } |
+ } |
+ static Annotation *Read(const u1 *&p) { |
+ Annotation *value = new Annotation; |
+ value->type_ = constant(get_u2be(p)); |
+ u2 num_element_value_pairs = get_u2be(p); |
+ for (int ii = 0; ii < num_element_value_pairs; ++ii) { |
+ ElementValuePair *pair = new ElementValuePair; |
+ pair->element_name_ = constant(get_u2be(p)); |
+ pair->element_value_ = ElementValue::Read(p); |
+ value->element_value_pairs_.push_back(pair); |
+ } |
+ return value; |
+ } |
+ Constant *type_; |
+ struct ElementValuePair { |
+ Constant *element_name_; |
+ ElementValue *element_value_; |
+ }; |
+ std::vector<ElementValuePair*> element_value_pairs_; |
+}; |
+ |
+// See sec 4.7.20 of Java 8 JVM Spec |
+// |
+// Each entry in the annotations table represents a single run-time visible |
+// annotation on a type used in a declaration or expression. The type_annotation |
+// structure has the following format: |
+// |
+// type_annotation { |
+// u1 target_type; |
+// union { |
+// type_parameter_target; |
+// supertype_target; |
+// type_parameter_bound_target; |
+// empty_target; |
+// method_formal_parameter_target; |
+// throws_target; |
+// localvar_target; |
+// catch_target; |
+// offset_target; |
+// type_argument_target; |
+// } target_info; |
+// type_path target_path; |
+// u2 type_index; |
+// u2 num_element_value_pairs; |
+// { |
+// u2 element_name_index; |
+// element_value value; |
+// } |
+// element_value_pairs[num_element_value_pairs]; |
+// } |
+// |
+struct TypeAnnotation { |
+ virtual ~TypeAnnotation() { |
+ delete target_info_; |
+ delete type_path_; |
+ delete annotation_; |
+ } |
+ |
+ void Write(u1 *&p) { |
+ put_u1(p, target_type_); |
+ target_info_->Write(p); |
+ type_path_->Write(p); |
+ annotation_->Write(p); |
+ } |
+ |
+ static TypeAnnotation *Read(const u1 *&p) { |
+ TypeAnnotation *value = new TypeAnnotation; |
+ value->target_type_ = get_u1(p); |
+ value->target_info_ = ReadTargetInfo(p, value->target_type_); |
+ value->type_path_ = TypePath::Read(p); |
+ value->annotation_ = Annotation::Read(p); |
+ return value; |
+ } |
+ |
+ struct TargetInfo { |
+ virtual ~TargetInfo() {} |
+ virtual void Write(u1 *&p) = 0; |
+ }; |
+ |
+ struct TypeParameterTargetInfo : TargetInfo { |
+ void Write(u1 *&p) { |
+ put_u1(p, type_parameter_index_); |
+ } |
+ static TypeParameterTargetInfo *Read(const u1 *&p) { |
+ TypeParameterTargetInfo *value = new TypeParameterTargetInfo; |
+ value->type_parameter_index_ = get_u1(p); |
+ return value; |
+ } |
+ u1 type_parameter_index_; |
+ }; |
+ |
+ struct ClassExtendsInfo : TargetInfo { |
+ void Write(u1 *&p) { |
+ put_u2be(p, supertype_index_); |
+ } |
+ static ClassExtendsInfo *Read(const u1 *&p) { |
+ ClassExtendsInfo *value = new ClassExtendsInfo; |
+ value->supertype_index_ = get_u2be(p); |
+ return value; |
+ } |
+ u2 supertype_index_; |
+ }; |
+ |
+ struct TypeParameterBoundInfo : TargetInfo { |
+ void Write(u1 *&p) { |
+ put_u1(p, type_parameter_index_); |
+ put_u1(p, bound_index_); |
+ } |
+ static TypeParameterBoundInfo *Read(const u1 *&p) { |
+ TypeParameterBoundInfo *value = new TypeParameterBoundInfo; |
+ value->type_parameter_index_ = get_u1(p); |
+ value->bound_index_ = get_u1(p); |
+ return value; |
+ } |
+ u1 type_parameter_index_; |
+ u1 bound_index_; |
+ }; |
+ |
+ struct EmptyInfo : TargetInfo { |
+ void Write(u1 *&p) {} |
+ static EmptyInfo *Read(const u1 *&p) { |
+ return new EmptyInfo; |
+ } |
+ }; |
+ |
+ struct MethodFormalParameterInfo : TargetInfo { |
+ void Write(u1 *&p) { |
+ put_u1(p, method_formal_parameter_index_); |
+ } |
+ static MethodFormalParameterInfo *Read(const u1 *&p) { |
+ MethodFormalParameterInfo *value = new MethodFormalParameterInfo; |
+ value->method_formal_parameter_index_ = get_u1(p); |
+ return value; |
+ } |
+ u1 method_formal_parameter_index_; |
+ }; |
+ |
+ struct ThrowsTypeInfo : TargetInfo { |
+ void Write(u1 *&p) { |
+ put_u2be(p, throws_type_index_); |
+ } |
+ static ThrowsTypeInfo *Read(const u1 *&p) { |
+ ThrowsTypeInfo *value = new ThrowsTypeInfo; |
+ value->throws_type_index_ = get_u2be(p); |
+ return value; |
+ } |
+ u2 throws_type_index_; |
+ }; |
+ |
+ static TargetInfo *ReadTargetInfo(const u1 *&p, u1 target_type) { |
+ switch (target_type) { |
+ case CLASS_TYPE_PARAMETER: |
+ case METHOD_TYPE_PARAMETER: |
+ return TypeParameterTargetInfo::Read(p); |
+ case CLASS_EXTENDS: |
+ return ClassExtendsInfo::Read(p); |
+ case CLASS_TYPE_PARAMETER_BOUND: |
+ case METHOD_TYPE_PARAMETER_BOUND: |
+ return TypeParameterBoundInfo::Read(p); |
+ case FIELD: |
+ case METHOD_RETURN: |
+ case METHOD_RECEIVER: |
+ return new EmptyInfo; |
+ case METHOD_FORMAL_PARAMETER: |
+ return MethodFormalParameterInfo::Read(p); |
+ case THROWS: |
+ return ThrowsTypeInfo::Read(p); |
+ default: |
+ fprintf(stderr, "Illegal type annotation target type: %d\n", |
+ target_type); |
+ abort(); |
+ } |
+ } |
+ |
+ struct TypePath { |
+ void Write(u1 *&p) { |
+ put_u1(p, path_.size()); |
+ for (TypePathEntry entry : path_) { |
+ put_u1(p, entry.type_path_kind_); |
+ put_u1(p, entry.type_argument_index_); |
+ } |
+ } |
+ static TypePath *Read(const u1 *&p) { |
+ TypePath *value = new TypePath; |
+ u1 path_length = get_u1(p); |
+ for (int ii = 0; ii < path_length; ++ii) { |
+ TypePathEntry entry; |
+ entry.type_path_kind_ = get_u1(p); |
+ entry.type_argument_index_ = get_u1(p); |
+ value->path_.push_back(entry); |
+ } |
+ return value; |
+ } |
+ |
+ struct TypePathEntry { |
+ u1 type_path_kind_; |
+ u1 type_argument_index_; |
+ }; |
+ std::vector<TypePathEntry> path_; |
+ }; |
+ |
+ u1 target_type_; |
+ TargetInfo *target_info_; |
+ TypePath *type_path_; |
+ Annotation *annotation_; |
+}; |
+ |
+struct AnnotationTypeElementValue : ElementValue { |
+ virtual ~AnnotationTypeElementValue() { |
+ delete annotation_; |
+ } |
+ |
+ void Write(u1 *&p) { |
+ put_u1(p, tag_); |
+ annotation_->Write(p); |
+ } |
+ static AnnotationTypeElementValue *Read(const u1 *&p) { |
+ AnnotationTypeElementValue *value = new AnnotationTypeElementValue; |
+ value->annotation_ = Annotation::Read(p); |
+ return value; |
+ } |
+ |
+ Annotation *annotation_; |
+}; |
+ |
+ElementValue* ElementValue::Read(const u1 *&p) { |
+ const u1* start = p; |
+ ElementValue *result; |
+ u1 tag = get_u1(p); |
+ if (tag != 0 && strchr("BCDFIJSZs", (char) tag) != NULL) { |
+ result = BaseTypeElementValue::Read(p); |
+ } else if ((char) tag == 'e') { |
+ result = EnumTypeElementValue::Read(p); |
+ } else if ((char) tag == 'c') { |
+ result = ClassTypeElementValue::Read(p); |
+ } else if ((char) tag == '[') { |
+ result = ArrayTypeElementValue::Read(p); |
+ } else if ((char) tag == '@') { |
+ result = AnnotationTypeElementValue::Read(p); |
+ } else { |
+ fprintf(stderr, "Illegal element_value::tag: %d\n", tag); |
+ abort(); |
+ } |
+ result->tag_ = tag; |
+ result->length_ = p - start; |
+ return result; |
+} |
+ |
+// See sec.4.7.20 of JVM spec. |
+// We preserve AnnotationDefault attributes because they are required |
+// in order to make use of an annotation in new code. |
+struct AnnotationDefaultAttribute : Attribute { |
+ virtual ~AnnotationDefaultAttribute() { |
+ delete default_value_; |
+ } |
+ |
+ static AnnotationDefaultAttribute* Read(const u1 *&p, |
+ Constant *attribute_name) { |
+ AnnotationDefaultAttribute *attr = new AnnotationDefaultAttribute; |
+ attr->attribute_name_ = attribute_name; |
+ attr->default_value_ = ElementValue::Read(p); |
+ return attr; |
+ } |
+ |
+ void Write(u1 *&p) { |
+ WriteProlog(p, default_value_->length_); |
+ default_value_->Write(p); |
+ } |
+ |
+ ElementValue *default_value_; |
+}; |
+ |
+// See sec.4.7.2 of JVM spec. |
+// We preserve ConstantValue attributes because they are required for |
+// compile-time constant propagation. |
+struct ConstantValueAttribute : Attribute { |
+ |
+ static ConstantValueAttribute* Read(const u1 *&p, Constant *attribute_name) { |
+ ConstantValueAttribute *attr = new ConstantValueAttribute; |
+ attr->attribute_name_ = attribute_name; |
+ attr->constantvalue_ = constant(get_u2be(p)); |
+ return attr; |
+ } |
+ |
+ void Write(u1 *&p) { |
+ WriteProlog(p, 2); |
+ put_u2be(p, constantvalue_->slot()); |
+ } |
+ |
+ Constant *constantvalue_; |
+}; |
+ |
+// See sec.4.7.9 of JVM spec. |
+// We preserve Signature attributes because they are required by the |
+// compiler for type-checking of generics. |
+struct SignatureAttribute : Attribute { |
+ |
+ static SignatureAttribute* Read(const u1 *&p, Constant *attribute_name) { |
+ SignatureAttribute *attr = new SignatureAttribute; |
+ attr->attribute_name_ = attribute_name; |
+ attr->signature_ = constant(get_u2be(p)); |
+ return attr; |
+ } |
+ |
+ void Write(u1 *&p) { |
+ WriteProlog(p, 2); |
+ put_u2be(p, signature_->slot()); |
+ } |
+ |
+ Constant *signature_; |
+}; |
+ |
+// See sec.4.7.15 of JVM spec. |
+// We preserve Deprecated attributes because they are required by the |
+// compiler to generate warning messages. |
+struct DeprecatedAttribute : Attribute { |
+ |
+ static DeprecatedAttribute* Read(const u1 *&p, Constant *attribute_name) { |
+ DeprecatedAttribute *attr = new DeprecatedAttribute; |
+ attr->attribute_name_ = attribute_name; |
+ return attr; |
+ } |
+ |
+ void Write(u1 *&p) { |
+ WriteProlog(p, 0); |
+ } |
+}; |
+ |
+// See sec.4.7.16-17 of JVM spec v3. Includes RuntimeVisible and |
+// RuntimeInvisible. |
+// |
+// We preserve all annotations. |
+struct AnnotationsAttribute : Attribute { |
+ virtual ~AnnotationsAttribute() { |
+ for (size_t i = 0; i < annotations_.size(); i++) { |
+ delete annotations_[i]; |
+ } |
+ } |
+ |
+ static AnnotationsAttribute* Read(const u1 *&p, Constant *attribute_name) { |
+ AnnotationsAttribute *attr = new AnnotationsAttribute; |
+ attr->attribute_name_ = attribute_name; |
+ u2 num_annotations = get_u2be(p); |
+ for (int ii = 0; ii < num_annotations; ++ii) { |
+ Annotation *annotation = Annotation::Read(p); |
+ attr->annotations_.push_back(annotation); |
+ } |
+ return attr; |
+ } |
+ |
+ void Write(u1 *&p) { |
+ WriteProlog(p, -1); |
+ u1 *payload_start = p - 4; |
+ put_u2be(p, annotations_.size()); |
+ for (size_t ii = 0; ii < annotations_.size(); ++ii) { |
+ annotations_[ii]->Write(p); |
+ } |
+ put_u4be(payload_start, p - 4 - payload_start); // backpatch length |
+ } |
+ |
+ std::vector<Annotation*> annotations_; |
+}; |
+ |
+// See sec.4.7.18-19 of JVM spec. Includes RuntimeVisible and |
+// RuntimeInvisible. |
+// |
+// We preserve all annotations. |
+struct ParameterAnnotationsAttribute : Attribute { |
+ |
+ static ParameterAnnotationsAttribute* Read(const u1 *&p, |
+ Constant *attribute_name) { |
+ ParameterAnnotationsAttribute *attr = new ParameterAnnotationsAttribute; |
+ attr->attribute_name_ = attribute_name; |
+ u1 num_parameters = get_u1(p); |
+ for (int ii = 0; ii < num_parameters; ++ii) { |
+ std::vector<Annotation*> annotations; |
+ u2 num_annotations = get_u2be(p); |
+ for (int ii = 0; ii < num_annotations; ++ii) { |
+ Annotation *annotation = Annotation::Read(p); |
+ annotations.push_back(annotation); |
+ } |
+ attr->parameter_annotations_.push_back(annotations); |
+ } |
+ return attr; |
+ } |
+ |
+ void Write(u1 *&p) { |
+ WriteProlog(p, -1); |
+ u1 *payload_start = p - 4; |
+ put_u1(p, parameter_annotations_.size()); |
+ for (size_t ii = 0; ii < parameter_annotations_.size(); ++ii) { |
+ std::vector<Annotation *> &annotations = parameter_annotations_[ii]; |
+ put_u2be(p, annotations.size()); |
+ for (size_t jj = 0; jj < annotations.size(); ++jj) { |
+ annotations[jj]->Write(p); |
+ } |
+ } |
+ put_u4be(payload_start, p - 4 - payload_start); // backpatch length |
+ } |
+ |
+ std::vector<std::vector<Annotation*> > parameter_annotations_; |
+}; |
+ |
+// See sec.4.7.20 of Java 8 JVM spec. Includes RuntimeVisibleTypeAnnotations |
+// and RuntimeInvisibleTypeAnnotations. |
+struct TypeAnnotationsAttribute : Attribute { |
+ static TypeAnnotationsAttribute* Read(const u1 *&p, Constant *attribute_name, |
+ u4 attribute_length) { |
+ auto attr = new TypeAnnotationsAttribute; |
+ attr->attribute_name_ = attribute_name; |
+ u2 num_annotations = get_u2be(p); |
+ for (int ii = 0; ii < num_annotations; ++ii) { |
+ TypeAnnotation *annotation = TypeAnnotation::Read(p); |
+ attr->type_annotations_.push_back(annotation); |
+ } |
+ return attr; |
+ } |
+ |
+ void Write(u1 *&p) { |
+ WriteProlog(p, -1); |
+ u1 *payload_start = p - 4; |
+ put_u2be(p, type_annotations_.size()); |
+ for (TypeAnnotation *annotation : type_annotations_) { |
+ annotation->Write(p); |
+ } |
+ put_u4be(payload_start, p - 4 - payload_start); // backpatch length |
+ } |
+ |
+ std::vector<TypeAnnotation*> type_annotations_; |
+}; |
+ |
+struct GeneralAttribute : Attribute { |
+ static GeneralAttribute* Read(const u1 *&p, Constant *attribute_name, |
+ u4 attribute_length) { |
+ auto attr = new GeneralAttribute; |
+ attr->attribute_name_ = attribute_name; |
+ attr->attribute_length_ = attribute_length; |
+ attr->attribute_content_ = p; |
+ p += attribute_length; |
+ return attr; |
+ } |
+ |
+ void Write(u1 *&p) { |
+ WriteProlog(p, attribute_length_); |
+ put_n(p, attribute_content_, attribute_length_); |
+ } |
+ |
+ u4 attribute_length_; |
+ const u1 *attribute_content_; |
+}; |
+ |
+/********************************************************************** |
+ * * |
+ * ClassFile * |
+ * * |
+ **********************************************************************/ |
+ |
+struct HasAttrs { |
+ std::vector<Attribute*> attributes; |
+ |
+ void WriteAttrs(u1 *&p); |
+ void ReadAttrs(const u1 *&p); |
+ |
+ virtual ~HasAttrs() { |
+ for (size_t i = 0; i < attributes.size(); i++) { |
+ delete attributes[i]; |
+ } |
+ } |
+}; |
+ |
+// A field or method. |
+// See sec.4.5 and 4.6 of JVM spec. |
+struct Member : HasAttrs { |
+ u2 access_flags; |
+ Constant *name; |
+ Constant *descriptor; |
+ |
+ static Member* Read(const u1 *&p) { |
+ Member *m = new Member; |
+ m->access_flags = get_u2be(p); |
+ m->name = constant(get_u2be(p)); |
+ m->descriptor = constant(get_u2be(p)); |
+ m->ReadAttrs(p); |
+ return m; |
+ } |
+ |
+ void Write(u1 *&p) { |
+ put_u2be(p, access_flags); |
+ put_u2be(p, name->slot()); |
+ put_u2be(p, descriptor->slot()); |
+ WriteAttrs(p); |
+ } |
+}; |
+ |
+// See sec.4.1 of JVM spec. |
+struct ClassFile : HasAttrs { |
+ |
+ size_t length; |
+ |
+ // Header: |
+ u4 magic; |
+ u2 major; |
+ u2 minor; |
+ |
+ // Body: |
+ u2 access_flags; |
+ Constant *this_class; |
+ Constant *super_class; |
+ std::vector<Constant*> interfaces; |
+ std::vector<Member*> fields; |
+ std::vector<Member*> methods; |
+ |
+ virtual ~ClassFile() { |
+ for (size_t i = 0; i < fields.size(); i++) { |
+ delete fields[i]; |
+ } |
+ |
+ for (size_t i = 0; i < methods.size(); i++) { |
+ delete methods[i]; |
+ } |
+ |
+ // Constants do not need to be deleted; they are owned by the constant pool. |
+ } |
+ |
+ void WriteClass(u1 *&p); |
+ |
+ bool ReadConstantPool(const u1 *&p); |
+ |
+ void StripIfAnonymous(); |
+ |
+ void WriteHeader(u1 *&p) { |
+ put_u4be(p, magic); |
+ put_u2be(p, major); |
+ put_u2be(p, minor); |
+ |
+ put_u2be(p, const_pool_out.size()); |
+ for (u2 ii = 1; ii < const_pool_out.size(); ++ii) { |
+ if (const_pool_out[ii] != NULL) { // NB: NULLs appear after long/double. |
+ const_pool_out[ii]->Write(p); |
+ } |
+ } |
+ } |
+ |
+ void WriteBody(u1 *&p) { |
+ put_u2be(p, access_flags); |
+ put_u2be(p, this_class->slot()); |
+ put_u2be(p, super_class == NULL ? 0 : super_class->slot()); |
+ put_u2be(p, interfaces.size()); |
+ for (size_t ii = 0; ii < interfaces.size(); ++ii) { |
+ put_u2be(p, interfaces[ii]->slot()); |
+ } |
+ put_u2be(p, fields.size()); |
+ for (size_t ii = 0; ii < fields.size(); ++ii) { |
+ fields[ii]->Write(p); |
+ } |
+ put_u2be(p, methods.size()); |
+ for (size_t ii = 0; ii < methods.size(); ++ii) { |
+ methods[ii]->Write(p); |
+ } |
+ WriteAttrs(p); |
+ } |
+ |
+}; |
+ |
+void HasAttrs::ReadAttrs(const u1 *&p) { |
+ u2 attributes_count = get_u2be(p); |
+ for (int ii = 0; ii < attributes_count; ii++) { |
+ Constant *attribute_name = constant(get_u2be(p)); |
+ u4 attribute_length = get_u4be(p); |
+ |
+ std::string attr_name = attribute_name->Display(); |
+ if (attr_name == "SourceFile" || |
+ attr_name == "LineNumberTable" || |
+ attr_name == "LocalVariableTable" || |
+ attr_name == "LocalVariableTypeTable" || |
+ attr_name == "Code" || |
+ attr_name == "Synthetic" || |
+ attr_name == "BootstrapMethods") { |
+ p += attribute_length; // drop these attributes |
+ } else if (attr_name == "Exceptions") { |
+ attributes.push_back(ExceptionsAttribute::Read(p, attribute_name)); |
+ } else if (attr_name == "Signature") { |
+ attributes.push_back(SignatureAttribute::Read(p, attribute_name)); |
+ } else if (attr_name == "Deprecated") { |
+ attributes.push_back(DeprecatedAttribute::Read(p, attribute_name)); |
+ } else if (attr_name == "EnclosingMethod") { |
+ attributes.push_back(EnclosingMethodAttribute::Read(p, attribute_name)); |
+ } else if (attr_name == "InnerClasses") { |
+ // TODO(bazel-team): omit private inner classes |
+ attributes.push_back(InnerClassesAttribute::Read(p, attribute_name)); |
+ } else if (attr_name == "AnnotationDefault") { |
+ attributes.push_back(AnnotationDefaultAttribute::Read(p, attribute_name)); |
+ } else if (attr_name == "ConstantValue") { |
+ attributes.push_back(ConstantValueAttribute::Read(p, attribute_name)); |
+ } else if (attr_name == "RuntimeVisibleAnnotations" || |
+ attr_name == "RuntimeInvisibleAnnotations") { |
+ attributes.push_back(AnnotationsAttribute::Read(p, attribute_name)); |
+ } else if (attr_name == "RuntimeVisibleParameterAnnotations" || |
+ attr_name == "RuntimeInvisibleParameterAnnotations") { |
+ attributes.push_back( |
+ ParameterAnnotationsAttribute::Read(p, attribute_name)); |
+ } else if (attr_name == "Scala" || |
+ attr_name == "ScalaSig" || |
+ attr_name == "ScalaInlineInfo") { |
+ // These are opaque blobs, so can be handled with a general |
+ // attribute handler |
+ attributes.push_back(GeneralAttribute::Read(p, attribute_name, |
+ attribute_length)); |
+ } else if (attr_name == "RuntimeVisibleTypeAnnotations" || |
+ attr_name == "RuntimeInvisibleTypeAnnotations") { |
+ // JSR 308: annotations on types. JDK 7 has no use for these yet, but the |
+ // Checkers Framework relies on them. |
+ attributes.push_back(TypeAnnotationsAttribute::Read(p, attribute_name, |
+ attribute_length)); |
+ } else { |
+ // Skip over unknown attributes with a warning. The JVM spec |
+ // says this is ok, so long as we handle the mandatory attributes. |
+ fprintf(stderr, "ijar: skipping unknown attribute: \"%s\".\n", |
+ attr_name.c_str()); |
+ p += attribute_length; |
+ } |
+ } |
+} |
+ |
+void HasAttrs::WriteAttrs(u1 *&p) { |
+ put_u2be(p, attributes.size()); |
+ for (size_t ii = 0; ii < attributes.size(); ii++) { |
+ attributes[ii]->Write(p); |
+ } |
+} |
+ |
+// See sec.4.4 of JVM spec. |
+bool ClassFile::ReadConstantPool(const u1 *&p) { |
+ |
+ const_pool_in.clear(); |
+ const_pool_in.push_back(NULL); // dummy first item |
+ |
+ u2 cp_count = get_u2be(p); |
+ for (int ii = 1; ii < cp_count; ++ii) { |
+ u1 tag = get_u1(p); |
+ |
+ if (devtools_ijar::verbose) { |
+ fprintf(stderr, "cp[%d/%d] = tag %d\n", ii, cp_count, tag); |
+ } |
+ |
+ switch(tag) { |
+ case CONSTANT_Class: { |
+ u2 name_index = get_u2be(p); |
+ const_pool_in.push_back(new Constant_Class(name_index)); |
+ break; |
+ } |
+ case CONSTANT_FieldRef: |
+ case CONSTANT_Methodref: |
+ case CONSTANT_Interfacemethodref: { |
+ u2 class_index = get_u2be(p); |
+ u2 nti = get_u2be(p); |
+ const_pool_in.push_back(new Constant_FMIref(tag, class_index, nti)); |
+ break; |
+ } |
+ case CONSTANT_String: { |
+ u2 string_index = get_u2be(p); |
+ const_pool_in.push_back(new Constant_String(string_index)); |
+ break; |
+ } |
+ case CONSTANT_NameAndType: { |
+ u2 name_index = get_u2be(p); |
+ u2 descriptor_index = get_u2be(p); |
+ const_pool_in.push_back( |
+ new Constant_NameAndType(name_index, descriptor_index)); |
+ break; |
+ } |
+ case CONSTANT_Utf8: { |
+ u2 length = get_u2be(p); |
+ if (devtools_ijar::verbose) { |
+ fprintf(stderr, "Utf8: \"%s\" (%d)\n", |
+ std::string((const char*) p, length).c_str(), length); |
+ } |
+ |
+ const_pool_in.push_back(new Constant_Utf8(length, p)); |
+ p += length; |
+ break; |
+ } |
+ case CONSTANT_Integer: |
+ case CONSTANT_Float: { |
+ u4 bytes = get_u4be(p); |
+ const_pool_in.push_back(new Constant_IntegerOrFloat(tag, bytes)); |
+ break; |
+ } |
+ case CONSTANT_Long: |
+ case CONSTANT_Double: { |
+ u4 high_bytes = get_u4be(p); |
+ u4 low_bytes = get_u4be(p); |
+ const_pool_in.push_back( |
+ new Constant_LongOrDouble(tag, high_bytes, low_bytes)); |
+ // Longs and doubles occupy two constant pool slots. |
+ // ("In retrospect, making 8-byte constants take two "constant |
+ // pool entries was a poor choice." --JVM Spec.) |
+ const_pool_in.push_back(NULL); |
+ ii++; |
+ break; |
+ } |
+ case CONSTANT_MethodHandle: { |
+ u1 reference_kind = get_u1(p); |
+ u2 reference_index = get_u2be(p); |
+ const_pool_in.push_back( |
+ new Constant_MethodHandle(reference_kind, reference_index)); |
+ break; |
+ } |
+ case CONSTANT_MethodType: { |
+ u2 descriptor_index = get_u2be(p); |
+ const_pool_in.push_back(new Constant_MethodType(descriptor_index)); |
+ break; |
+ } |
+ case CONSTANT_InvokeDynamic: { |
+ u2 bootstrap_method_attr = get_u2be(p); |
+ u2 name_name_type_index = get_u2be(p); |
+ const_pool_in.push_back(new Constant_InvokeDynamic( |
+ bootstrap_method_attr, name_name_type_index)); |
+ break; |
+ } |
+ default: { |
+ fprintf(stderr, "Unknown constant: %02x. Passing class through.\n", |
+ tag); |
+ return false; |
+ } |
+ } |
+ } |
+ |
+ return true; |
+} |
+ |
+// Anonymous inner classes are stripped to opaque classes that only extend |
+// Object. None of their methods or fields are accessible anyway. |
+void ClassFile::StripIfAnonymous() { |
+ int enclosing_index = -1; |
+ int inner_classes_index = -1; |
+ |
+ for (size_t ii = 0; ii < attributes.size(); ++ii) { |
+ if (attributes[ii]->attribute_name_->Display() == "EnclosingMethod") { |
+ enclosing_index = ii; |
+ } else if (attributes[ii]->attribute_name_->Display() == "InnerClasses") { |
+ inner_classes_index = ii; |
+ } |
+ } |
+ |
+ // Presence of an EnclosingMethod attribute indicates a local or anonymous |
+ // class, which can be stripped. |
+ if (enclosing_index > -1) { |
+ // Clear the signature to only extend java.lang.Object. |
+ super_class = NULL; |
+ interfaces.clear(); |
+ |
+ // Clear away all fields (implementation details). |
+ for (size_t ii = 0; ii < fields.size(); ++ii) { |
+ delete fields[ii]; |
+ } |
+ fields.clear(); |
+ |
+ // Clear away all methods (implementation details). |
+ for (size_t ii = 0; ii < methods.size(); ++ii) { |
+ delete methods[ii]; |
+ } |
+ methods.clear(); |
+ |
+ // Only preserve the InnerClasses attribute to comply with the spec. |
+ Attribute *attr = NULL; |
+ for (size_t ii = 0; ii < attributes.size(); ++ii) { |
+ if (static_cast<int>(ii) != inner_classes_index) { |
+ delete attributes[ii]; |
+ } else { |
+ attr = attributes[ii]; |
+ } |
+ } |
+ attributes.clear(); |
+ if (attr != NULL) { |
+ attributes.push_back(attr); |
+ } |
+ } |
+} |
+ |
+static ClassFile *ReadClass(const void *classdata, size_t length) { |
+ const u1 *p = (u1*) classdata; |
+ |
+ ClassFile *clazz = new ClassFile; |
+ |
+ clazz->length = length; |
+ |
+ clazz->magic = get_u4be(p); |
+ if (clazz->magic != 0xCAFEBABE) { |
+ fprintf(stderr, "Bad magic %" PRIx32 "\n", clazz->magic); |
+ abort(); |
+ } |
+ clazz->major = get_u2be(p); |
+ clazz->minor = get_u2be(p); |
+ |
+ if (!clazz->ReadConstantPool(p)) { |
+ delete clazz; |
+ return NULL; |
+ } |
+ |
+ clazz->access_flags = get_u2be(p); |
+ clazz->this_class = constant(get_u2be(p)); |
+ u2 super_class_id = get_u2be(p); |
+ clazz->super_class = super_class_id == 0 ? NULL : constant(super_class_id); |
+ |
+ u2 interfaces_count = get_u2be(p); |
+ for (int ii = 0; ii < interfaces_count; ++ii) { |
+ clazz->interfaces.push_back(constant(get_u2be(p))); |
+ } |
+ |
+ u2 fields_count = get_u2be(p); |
+ for (int ii = 0; ii < fields_count; ++ii) { |
+ Member *field = Member::Read(p); |
+ |
+ if (!(field->access_flags & ACC_PRIVATE)) { // drop private fields |
+ clazz->fields.push_back(field); |
+ } |
+ } |
+ |
+ u2 methods_count = get_u2be(p); |
+ for (int ii = 0; ii < methods_count; ++ii) { |
+ Member *method = Member::Read(p); |
+ |
+ // drop class initializers |
+ if (method->name->Display() == "<clinit>") continue; |
+ |
+ if (!(method->access_flags & ACC_PRIVATE)) { // drop private methods |
+ clazz->methods.push_back(method); |
+ } |
+ } |
+ |
+ clazz->ReadAttrs(p); |
+ clazz->StripIfAnonymous(); |
+ |
+ return clazz; |
+} |
+ |
+void ClassFile::WriteClass(u1 *&p) { |
+ // We have to write the body out before the header in order to reference |
+ // the essential constants and populate the output constant pool: |
+ u1 *body = new u1[length]; |
+ u1 *q = body; |
+ WriteBody(q); // advances q |
+ u4 body_length = q - body; |
+ |
+ WriteHeader(p); // advances p |
+ put_n(p, body, body_length); |
+ delete[] body; |
+} |
+ |
+ |
+void StripClass(u1 *&classdata_out, const u1 *classdata_in, size_t in_length) { |
+ ClassFile *clazz = ReadClass(classdata_in, in_length); |
+ if (clazz == NULL) { |
+ // Class is invalid. Simply copy it to the output and call it a day. |
+ put_n(classdata_out, classdata_in, in_length); |
+ } else { |
+ |
+ // Constant pool item zero is a dummy entry. Setting it marks the |
+ // beginning of the output phase; calls to Constant::slot() will |
+ // fail if called prior to this. |
+ const_pool_out.push_back(NULL); |
+ |
+ // TODO(bazel-team): We should only keep classes in the InnerClass attributes |
+ // if they're used in the output. The entries can then be cleaned out of the |
+ // constant pool in the normal way. |
+ |
+ clazz->WriteClass(classdata_out); |
+ |
+ delete clazz; |
+ } |
+ |
+ // Now clean up all the mess we left behind. |
+ |
+ for (size_t i = 0; i < const_pool_in.size(); i++) { |
+ delete const_pool_in[i]; |
+ } |
+ |
+ const_pool_in.clear(); |
+ const_pool_out.clear(); |
+} |
+ |
+} // namespace devtools_ijar |