Index: vm/vmcore/include/class_member.h
===================================================================
--- vm/vmcore/include/class_member.h (revision 483534)
+++ vm/vmcore/include/class_member.h (working copy)
@@ -131,13 +131,6 @@
bool parse(Class* clss, ByteReader& cfs);
- /*
- * returns ATTR_ERROR if attribute was recognized but parsing failed;
- * returns ATTR_UNDEF if attribute was not recognized
- * otherwise returns passed attr value
- */
- Attributes process_common_attribute(Attributes attr, uint32 attr_len, ByteReader& cfs);
-
public:
#ifdef VM_STATS
uint64 num_accesses;
@@ -432,6 +425,11 @@
};
State get_state() {return _state;}
void set_state(State st) {_state=st;}
+
+ struct LocalVarOffset{
+ int value;
+ LocalVarOffset* next;
+ };
// "Bytecode" exception handlers, i.e., those from the class file
unsigned num_bc_exception_handlers() const { return _n_handlers; }
@@ -483,7 +481,7 @@
// Returns number of bytes of arguments pushed on the stack.
// This value depends on the descriptor and the calling convention.
- unsigned get_num_arg_bytes() const { return _arguments_size; }
+ unsigned get_num_arg_slots() const { return _arguments_slot_num; }
// Returns number of arguments. For non-static methods, the this pointer
// is included in this number
@@ -625,8 +623,8 @@
bool parse(Global_Env& env, Class* clss, ByteReader& cfs);
- void calculate_arguments_size();
-
+ void calculate_arguments_slot_num();
+
unsigned calculate_size() {
unsigned size = sizeof(Class_Member) + sizeof(Method);
if(_local_vars_table)
@@ -651,7 +649,7 @@
AnnotationValue * _default_value;
unsigned _index; // index in method table
- unsigned _arguments_size; // size of method arguments on the stack
+ unsigned _arguments_slot_num; // number of slots for method arguments
uint16 _max_stack;
uint16 _max_locals;
uint16 _n_exceptions; // num exceptions method can throw
@@ -687,8 +685,8 @@
Line_Number_Table *_line_number_table;
Local_Var_Table *_local_vars_table;
- bool _parse_local_vars(const char* attr_name, Local_Var_Table** lvt_address,
- ConstantPool& cp, unsigned attr_len, ByteReader &cfs);
+ bool _parse_local_vars(Local_Var_Table* table, LocalVarOffset* offset_list,
+ ConstantPool& cp, ByteReader &cfs, const char* attr_name, Attributes attr);
// This is the number of breakpoints which should be set in the
// method when it is compiled. This number does not reflect
Index: vm/vmcore/include/Class.h
===================================================================
--- vm/vmcore/include/Class.h (revision 483534)
+++ vm/vmcore/include/Class.h (working copy)
@@ -225,7 +225,9 @@
* @return true if the index is a valid one in the constant
* pool; otherwise false.*/
bool is_valid_index(uint16 index) const {
- return /*index > 0 && */index < m_size;
+ // index is valid if it's greater than zero and less than m_size
+ // See specification 4.2 about constant_pool_count
+ return index > 0 && index < m_size;
}
/** Checks whether the constant-pool entry is resolved.
@@ -632,7 +634,7 @@
* @param[in] clss - the class that the given constant pool belongs to
* @return true if the constant pool of clss is valid;
* otherwise false.*/
- bool check(Class* clss);
+ bool check(Global_Env *, Class* clss);
/** Clears the constant-pool content: tags and entries arrays.*/
void clear() {
@@ -1435,6 +1437,12 @@
* flag is set.
* @return true if the class is enum.*/
bool is_enum() const { return (m_access_flags & ACC_ENUM) != 0; }
+
+ /** Checks whether the class has the ACC_SYNTHETIC flag set.
+ * @return true if the class has the ACC_SYNTHETIC
+ * access flag set.*/
+
+ bool is_synthetic() const { return (m_access_flags & ACC_SYNTHETIC) != 0; }
/** Checks whether the class is an annotation.
* @return true if the class is an annotation.*/
Index: vm/vmcore/src/jit/jit_runtime_support.cpp
===================================================================
--- vm/vmcore/src/jit/jit_runtime_support.cpp (revision 483534)
+++ vm/vmcore/src/jit/jit_runtime_support.cpp (working copy)
@@ -2093,7 +2093,7 @@
}
// Every argument is at least 4 bytes long
- int num_args_estimate = constructor->get_num_arg_bytes() / 4;
+ int num_args_estimate = constructor->get_num_arg_slots();
jvalue* args = (jvalue*)STD_MALLOC(num_args_estimate * sizeof(jvalue));
args[0].l = (jobject)obj;
Index: vm/vmcore/src/jvmti/jvmti_method.cpp
===================================================================
--- vm/vmcore/src/jvmti/jvmti_method.cpp (revision 483534)
+++ vm/vmcore/src/jvmti/jvmti_method.cpp (working copy)
@@ -236,7 +236,7 @@
if( !method ) return JVMTI_ERROR_NULL_POINTER;
if( !size_ptr ) return JVMTI_ERROR_NULL_POINTER;
- *size_ptr = reinterpret_cast(method)->get_num_arg_bytes() / 4;
+ *size_ptr = reinterpret_cast(method)->get_num_arg_slots();
return JVMTI_ERROR_NONE;
}
Index: vm/vmcore/src/exception/exceptions_jit.cpp
===================================================================
--- vm/vmcore/src/exception/exceptions_jit.cpp (revision 483534)
+++ vm/vmcore/src/exception/exceptions_jit.cpp (working copy)
@@ -575,7 +575,7 @@
ABORT("Lazy exceptions are not supported on this platform");
#else
uint8 *args = (uint8 *) (m2n_get_args(m2n_get_last_frame()) + 1); // +1 to skip constructor
- args += exn_constr->get_num_arg_bytes() - 4;
+ args += exn_constr->get_num_arg_slots() * 4 - 4;
exn_athrow(NULL, *(Class_Handle *) args, exn_constr, args);
#endif
} //rth_throw_lazy
Index: vm/vmcore/src/class_support/Prepare.cpp
===================================================================
--- vm/vmcore/src/class_support/Prepare.cpp (revision 483534)
+++ vm/vmcore/src/class_support/Prepare.cpp (working copy)
@@ -630,7 +630,7 @@
fake_method->_access_flags = (ACC_PUBLIC | ACC_ABSTRACT);
// Setting its "_intf_method_for_fake_method" field marks the method as being fake.
fake_method->_intf_method_for_fake_method = intf_method;
- fake_method->_arguments_size = intf_method->_arguments_size;
+ fake_method->_arguments_slot_num = intf_method->_arguments_slot_num;
// The rest of the method's fields were zero'd above
}
}
Index: vm/vmcore/src/class_support/method.cpp
===================================================================
--- vm/vmcore/src/class_support/method.cpp (revision 483534)
+++ vm/vmcore/src/class_support/method.cpp (working copy)
@@ -201,14 +201,13 @@
} //Method::get_target_exception_handler_info
-void Method::calculate_arguments_size()
+void Method::calculate_arguments_slot_num()
{
- // Use this old scheme until we can use the new JIT interface's methods
- // to inspect the types of each method argument. This requires that these
- // methods support Java, and that they work during VM's bootstrapping.
- unsigned nb = 0;
+ //This method counts length of method parameters in slots.
+ //See 4.4.3 paragraph 5 in specification.
+ unsigned slot_num = 0;
if (!is_static()) {
- nb = 4;
+ slot_num = 1;
}
Arg_List_Iterator iter = get_argument_list();
Java_Type typ;
@@ -216,19 +215,17 @@
switch(typ) {
case JAVA_TYPE_LONG:
case JAVA_TYPE_DOUBLE:
- nb += 8;
+ slot_num += 2;
break;
default:
- nb += 4;
+ slot_num += 1;
break;
}
iter = advance_arg_iterator(iter);
}
- _arguments_size = nb;
-} // Method::get_num_arg_bytes
+ _arguments_slot_num = slot_num;
+} // Method::calculate_arguments_slot_num
-
-
unsigned Method::get_num_ref_args()
{
unsigned nargs;
Index: vm/vmcore/src/class_support/Class_File_Loader.cpp
===================================================================
--- vm/vmcore/src/class_support/Class_File_Loader.cpp (revision 483534)
+++ vm/vmcore/src/class_support/Class_File_Loader.cpp (working copy)
@@ -14,10 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/**
+/**
* @author Pavel Pervov, Alexey V. Varlamov
* @version $Revision: 1.1.2.6.4.6 $
- */
+ */
#define LOG_DOMAIN util::CLASS_LOGGER
#include "cxxlog.h"
@@ -47,15 +47,15 @@
*/
//
-// To do:
+// TODO list:
//
-// (1) Check that ConstantValue attribute's type matches field's type
-// (2) Set the value field of Field, when ConstantValue is parsed
-// (3) verify correctness of Method access_flags (see pg 115 of the JVM spec)
-// (4) verify correctness of Field access_flags (pg 113 of the JVM spec)
-// (5) verify Class access_flags (pg 96 of the JVM spec)
-// (6) verify that for interfaces, super is always java.lang.Object (pg 36)
-// (7) interfaces cannot have super classes (assumed in preparation)
+// (1) verify correctness of Method access_flags for different class file versions
+// (2) verify correctness of Field access_flags for different class file versions
+// (3) verify Class access_flags for different class file versions
+// (4) check that Signature of attribute LocalVariableTypeTable of Code attribute is valid
+// (5) implement functionality of RuntimeInvisibleAnnotations
+// and RuntimeInvisibleParameterAnnotations, not just skip them
+// (6) check Signature attribute, not only parse it
//
#define REPORT_FAILED_CLASS_FORMAT(klass, msg) \
@@ -83,62 +83,39 @@
static String* cp_check_class(ConstantPool& cp, unsigned class_index)
{
+ //See specification 4.2 about valid index and 4.5.1 about tag value
if(!cp.is_valid_index(class_index) || !cp.is_class(class_index)) {
+
#ifdef _DEBUG
WARN("cp_check_class: illegal const pool class index" << class_index);
#endif
return NULL;
- }
+ }
return cp.get_utf8_string(cp.get_class_name_index(class_index));
} //cp_check_class
-
-#define N_COMMON_ATTR 5
-#define N_FIELD_ATTR 1
-#define N_METHOD_ATTR 5
+#define N_FIELD_ATTR 6
+#define N_METHOD_ATTR 10
#define N_CODE_ATTR 3
-#define N_CLASS_ATTR 4
+#define N_CLASS_ATTR 9
-static String *common_attr_strings[N_COMMON_ATTR+1];
-static Attributes common_attrs[N_COMMON_ATTR];
-
-static String *field_attr_strings[N_FIELD_ATTR+1];
+static String *field_attr_strings[N_FIELD_ATTR+1]; //attributes required to be recognized for fields
static Attributes field_attrs[N_FIELD_ATTR];
-static String *method_attr_strings[N_METHOD_ATTR+1];
+static String *method_attr_strings[N_METHOD_ATTR+1]; //attributes required to be recognized for methods
static Attributes method_attrs[N_METHOD_ATTR];
-static String *class_attr_strings[N_CLASS_ATTR+1];
+static String *class_attr_strings[N_CLASS_ATTR+1]; //attributes required to be recognized for class
static Attributes class_attrs[N_CLASS_ATTR];
-static String *code_attr_strings[N_CODE_ATTR+1];
+static String *code_attr_strings[N_CODE_ATTR+1]; //attributes required to be recognized for code attribute
static Attributes code_attrs[N_CODE_ATTR];
-static String *must_recognize_attr_strings[5];
-static Attributes must_recognize_attrs[4];
-
//
// initialize string pool by preloading it with commonly used strings
//
static bool preload_attrs(String_Pool& string_pool)
{
- common_attr_strings[0] = string_pool.lookup("Synthetic");
- common_attrs[0] = ATTR_Synthetic;
-
- common_attr_strings[1] = string_pool.lookup("Deprecated");
- common_attrs[1] = ATTR_Deprecated;
-
- common_attr_strings[2] = string_pool.lookup("Signature");
- common_attrs[2] = ATTR_Signature;
-
- common_attr_strings[3] = string_pool.lookup("RuntimeVisibleAnnotations");
- common_attrs[3] = ATTR_RuntimeVisibleAnnotations;
-
- common_attr_strings[4] = string_pool.lookup("RuntimeInvisibleAnnotations");
- common_attrs[4] = ATTR_RuntimeInvisibleAnnotations;
-
- common_attr_strings[5] = NULL;
-
method_attr_strings[0] = string_pool.lookup("Code");
method_attrs[0] = ATTR_Code;
@@ -154,13 +131,43 @@
method_attr_strings[4] = string_pool.lookup("AnnotationDefault");
method_attrs[4] = ATTR_AnnotationDefault;
- method_attr_strings[5] = NULL;
+ method_attr_strings[5] = string_pool.lookup("Synthetic");
+ method_attrs[5] = ATTR_Synthetic;
+ method_attr_strings[6] = string_pool.lookup("Deprecated");
+ method_attrs[6] = ATTR_Deprecated;
+
+ method_attr_strings[7] = string_pool.lookup("Signature");
+ method_attrs[7] = ATTR_Signature;
+
+ method_attr_strings[8] = string_pool.lookup("RuntimeVisibleAnnotations");
+ method_attrs[8] = ATTR_RuntimeVisibleAnnotations;
+
+ method_attr_strings[9] = string_pool.lookup("RuntimeInvisibleAnnotations");
+ method_attrs[9] = ATTR_RuntimeInvisibleAnnotations;
+
+ method_attr_strings[10] = NULL;
+
field_attr_strings[0] = string_pool.lookup("ConstantValue");
field_attrs[0] = ATTR_ConstantValue;
- field_attr_strings[1] = NULL;
+ field_attr_strings[1] = string_pool.lookup("Synthetic");
+ field_attrs[1] = ATTR_Synthetic;
+ field_attr_strings[2] = string_pool.lookup("Deprecated");
+ field_attrs[2] = ATTR_Deprecated;
+
+ field_attr_strings[3] = string_pool.lookup("Signature");
+ field_attrs[3] = ATTR_Signature;
+
+ field_attr_strings[4] = string_pool.lookup("RuntimeVisibleAnnotations");
+ field_attrs[4] = ATTR_RuntimeVisibleAnnotations;
+
+ field_attr_strings[5] = string_pool.lookup("RuntimeInvisibleAnnotations");
+ field_attrs[5] = ATTR_RuntimeInvisibleAnnotations;
+
+ field_attr_strings[6] = NULL;
+
class_attr_strings[0] = string_pool.lookup("SourceFile");
class_attrs[0] = ATTR_SourceFile;
@@ -172,9 +179,24 @@
class_attr_strings[3] = string_pool.lookup("EnclosingMethod");
class_attrs[3] = ATTR_EnclosingMethod;
-
- class_attr_strings[4] = NULL;
+ class_attr_strings[4] = string_pool.lookup("Synthetic");
+ class_attrs[4] = ATTR_Synthetic;
+
+ class_attr_strings[5] = string_pool.lookup("Deprecated");
+ class_attrs[5] = ATTR_Deprecated;
+
+ class_attr_strings[6] = string_pool.lookup("Signature");
+ class_attrs[6] = ATTR_Signature;
+
+ class_attr_strings[7] = string_pool.lookup("RuntimeVisibleAnnotations");
+ class_attrs[7] = ATTR_RuntimeVisibleAnnotations;
+
+ class_attr_strings[8] = string_pool.lookup("RuntimeInvisibleAnnotations");
+ class_attrs[8] = ATTR_RuntimeInvisibleAnnotations;
+
+ class_attr_strings[9] = NULL;
+
code_attr_strings[0] = string_pool.lookup("LineNumberTable");
code_attrs[0] = ATTR_LineNumberTable;
@@ -186,36 +208,23 @@
code_attr_strings[3] = NULL;
- must_recognize_attr_strings[0] = string_pool.lookup("Code");
- must_recognize_attrs[0] = ATTR_Code;
-
- must_recognize_attr_strings[1] = string_pool.lookup("ConstantValue");
- must_recognize_attrs[1] = ATTR_ConstantValue;
-
- must_recognize_attr_strings[2] = string_pool.lookup("Exceptions");
- must_recognize_attrs[2] = ATTR_Exceptions;
-
- must_recognize_attr_strings[3] = string_pool.lookup("Signature");
- must_recognize_attrs[3] = ATTR_Signature;
-
- must_recognize_attr_strings[4] = NULL;
-
return true;
} //init_loader
String* parse_signature_attr(ByteReader &cfs,
- uint32 attr_len,
- Class* clss)
+ uint32 attr_len,
+ Class* clss)
{
+ //See specification 4.8.8 about attribute length
if (attr_len != 2) {
- REPORT_FAILED_CLASS_FORMAT(clss,
+ REPORT_FAILED_CLASS_FORMAT(clss,
"unexpected length of Signature attribute : " << attr_len);
return NULL;
}
uint16 idx;
if (!cfs.parse_u2_be(&idx)) {
- REPORT_FAILED_CLASS_FORMAT(clss,
+ REPORT_FAILED_CLASS_FORMAT(clss,
"cannot parse Signature index");
return NULL;
}
@@ -227,60 +236,50 @@
}
-Attributes parse_attribute(ByteReader &cfs,
+Attributes parse_attribute(Class *clss,
+ ByteReader &cfs,
ConstantPool& cp,
String *attr_strings[],
Attributes attrs[],
- uint32 *attr_len,
- bool use_common = true)
+ uint32 *attr_len)
{
static bool UNUSED init = preload_attrs(VM_Global_State::loader_env->string_pool);
-
+ //See specification 4.8 about Attributes
uint16 attr_name_index;
bool result = cfs.parse_u2_be(&attr_name_index);
if (!result)
+ {
+ REPORT_FAILED_CLASS_FORMAT(clss,
+ "cannot parse attr_name_index");
return ATTR_ERROR;
-
+ }
result = cfs.parse_u4_be(attr_len);
if (!result)
+ {
+ REPORT_FAILED_CLASS_FORMAT(clss,
+ "parse attribute:cannot parse attribute length");
return ATTR_ERROR;
-
+ }
String* attr_name = cp_check_utf8(cp, attr_name_index);
- if (attr_name == NULL) {
-#ifdef _DEBUG
- WARN("parse_attribute: illegal const pool attr_name_index");
-#endif
+ if (attr_name == NULL)
+ {
+ REPORT_FAILED_CLASS_FORMAT(clss,
+ "parse_attribute: illegal const pool attr_name_index");
return ATTR_ERROR;
}
- unsigned i;
- if (use_common) {
- for (i=0; common_attr_strings[i] != NULL; i++) {
- if (common_attr_strings[i] == attr_name)
- return common_attrs[i];
- }
- }
- for (i=0; attr_strings[i] != NULL; i++) {
+ for (unsigned i=0; attr_strings[i] != NULL; i++) {
if (attr_strings[i] == attr_name)
return attrs[i];
}
//
// unrecognized attribute; skip
//
- uint32 length = *attr_len;
- while ( length-- > 0) {
- uint8 val;
- bool result = cfs.parse_u1(&val);
- if(!result)
+ if(!cfs.skip(*attr_len))
+ {
+ REPORT_FAILED_CLASS_FORMAT(clss,
+ "Couldn't skip unrecognized attribute: " << attr_name->bytes);
return ATTR_ERROR;
}
- // Code, ConstantValue, Exceptions must be recognized even if illegal in
- // a particular context
- for (i = 0; must_recognize_attr_strings[i] != NULL; i++) {
- if (must_recognize_attr_strings[i] == attr_name) {
- return must_recognize_attrs[i];
- }
- }
-
return ATTR_UNDEF;
} //parse_attribute
@@ -288,30 +287,30 @@
uint32 parse_annotation_value(AnnotationValue& value, ByteReader& cfs, Class* clss);
// returns number of read bytes, 0 if error occurred
-uint32 parse_annotation(Annotation** value, ByteReader& cfs, Class* clss)
+uint32 parse_annotation(Annotation** value, ByteReader& cfs, Class* clss)
{
uint16 type_idx;
if (!cfs.parse_u2_be(&type_idx)) {
- REPORT_FAILED_CLASS_FORMAT(clss,
+ REPORT_FAILED_CLASS_FORMAT(clss,
"cannot parse type index of annotation");
return 0;
}
String* type = cp_check_utf8(clss->get_constant_pool(), type_idx);
if (type == NULL) {
- REPORT_FAILED_CLASS_FORMAT(clss,
+ REPORT_FAILED_CLASS_FORMAT(clss,
"invalid type index of annotation : " << type_idx);
return 0;
}
uint16 num_elements;
if (!cfs.parse_u2_be(&num_elements)) {
- REPORT_FAILED_CLASS_FORMAT(clss,
+ REPORT_FAILED_CLASS_FORMAT(clss,
"cannot parse number of annotation elements");
return 0;
}
-
Annotation* antn = (Annotation*) clss->get_class_loader()->Alloc(
sizeof(Annotation) + num_elements * sizeof(AnnotationElement));
+ //FIXME: verav should throw OOM
antn->type = type;
antn->num_elements = num_elements;
antn->elements = (AnnotationElement*)((POINTER_SIZE_INT)antn + sizeof(Annotation));
@@ -323,13 +322,13 @@
{
uint16 name_idx;
if (!cfs.parse_u2_be(&name_idx)) {
- REPORT_FAILED_CLASS_FORMAT(clss,
+ REPORT_FAILED_CLASS_FORMAT(clss,
"cannot parse element_name_index of annotation element");
return 0;
}
antn->elements[j].name = cp_check_utf8(clss->get_constant_pool(), name_idx);
if (antn->elements[j].name == NULL) {
- REPORT_FAILED_CLASS_FORMAT(clss,
+ REPORT_FAILED_CLASS_FORMAT(clss,
"invalid element_name_index of annotation : " << name_idx);
return 0;
}
@@ -349,7 +348,7 @@
{
uint8 tag;
if (!cfs.parse_u1(&tag)) {
- REPORT_FAILED_CLASS_FORMAT(clss,
+ REPORT_FAILED_CLASS_FORMAT(clss,
"cannot parse annotation value tag");
return 0;
}
@@ -373,7 +372,7 @@
{
uint16 const_idx;
if (!cfs.parse_u2_be(&const_idx)) {
- REPORT_FAILED_CLASS_FORMAT(clss,
+ REPORT_FAILED_CLASS_FORMAT(clss,
"cannot parse const index of annotation value");
return 0;
}
@@ -382,54 +381,54 @@
case AVT_BYTE:
case AVT_SHORT:
case AVT_CHAR:
- case AVT_INT:
+ case AVT_INT:
if (valid_cpi(clss, const_idx, CONSTANT_Integer)) {
value.const_value.i = cp.get_int(const_idx);
break;
}
- case AVT_FLOAT:
+ case AVT_FLOAT:
if (valid_cpi(clss, const_idx, CONSTANT_Float)) {
value.const_value.f = cp.get_float(const_idx);
break;
}
- case AVT_LONG:
+ case AVT_LONG:
if (valid_cpi(clss, const_idx, CONSTANT_Long)) {
value.const_value.l.lo_bytes = cp.get_8byte_low_word(const_idx);
value.const_value.l.hi_bytes = cp.get_8byte_high_word(const_idx);
break;
}
- case AVT_DOUBLE:
+ case AVT_DOUBLE:
if (valid_cpi(clss, const_idx, CONSTANT_Double)) {
value.const_value.l.lo_bytes = cp.get_8byte_low_word(const_idx);
value.const_value.l.hi_bytes = cp.get_8byte_high_word(const_idx);
break;
}
- case AVT_STRING:
+ case AVT_STRING:
if (valid_cpi(clss, const_idx, CONSTANT_Utf8)) {
value.const_value.string = cp.get_utf8_string(const_idx);
break;
}
default:
- REPORT_FAILED_CLASS_FORMAT(clss,
+ REPORT_FAILED_CLASS_FORMAT(clss,
"invalid const index " << const_idx
<< " of annotation value of type " <get_class_loader()->Alloc(
num * sizeof(AnnotationValue));
+ //FIXME: verav should throw OOM
for (int i = 0; i < num; i++) {
uint32 size = parse_annotation_value(value.array.items[i], cfs, clss);
if (size == 0) {
@@ -502,7 +502,7 @@
break;
default:
- REPORT_FAILED_CLASS_FORMAT(clss,
+ REPORT_FAILED_CLASS_FORMAT(clss,
"unrecognized annotation value tag : " << ctag);
return 0;
}
@@ -511,11 +511,11 @@
}
// returns number of read bytes, 0 if error occurred
-uint32 parse_annotation_table(AnnotationTable ** table, ByteReader& cfs, Class* clss)
+uint32 parse_annotation_table(AnnotationTable ** table, ByteReader& cfs, Class* clss)
{
uint16 num_annotations;
if (!cfs.parse_u2_be(&num_annotations)) {
- REPORT_FAILED_CLASS_FORMAT(clss,
+ REPORT_FAILED_CLASS_FORMAT(clss,
"cannot parse number of Annotations");
return 0;
}
@@ -524,6 +524,7 @@
if (num_annotations) {
*table = (AnnotationTable*) clss->get_class_loader()->Alloc(
sizeof (AnnotationTable) + (num_annotations - 1)*sizeof(Annotation*));
+ //FIXME:verav should throw OOM
(*table)->length = num_annotations;
for (unsigned i = 0; i < num_annotations; i++)
@@ -541,71 +542,6 @@
return read_len;
}
-
-Attributes Class_Member::process_common_attribute(Attributes attr, uint32 attr_len, ByteReader& cfs)
-{
- switch(attr) {
- case ATTR_Synthetic:
- if(attr_len != 0) {
- REPORT_FAILED_CLASS_FORMAT(_class,
- "non-zero length of Synthetic attribute for class member "
- << _name->bytes << " " <<_descriptor->bytes );
- return ATTR_ERROR;
- }
- _synthetic = true;
- _access_flags |= ACC_SYNTHETIC;
- break;
-
- case ATTR_Deprecated:
- if(attr_len != 0) {
- REPORT_FAILED_CLASS_FORMAT(_class,
- "non-zero length of Deprecated attribute for class member "
- << _name->bytes << " " <<_descriptor->bytes );
- return ATTR_ERROR;
- }
- _deprecated = true;
- break;
-
- case ATTR_Signature:
- {
- if (!(_signature = parse_signature_attr(cfs, attr_len, _class))) {
- return ATTR_ERROR;
- }
- }
- break;
-
- case ATTR_RuntimeVisibleAnnotations:
- {
- uint32 read_len = parse_annotation_table(&_annotations, cfs, _class);
- if (read_len == 0) {
- return ATTR_ERROR;
- } else if (attr_len != read_len) {
- REPORT_FAILED_CLASS_FORMAT(_class,
- "error parsing Annotations attribute for class member "
- << _name->bytes << " " <<_descriptor->bytes
- << "; declared length " << attr_len
- << " does not match actual " << read_len);
- return ATTR_ERROR;
- }
- }
- break;
-
- case ATTR_RuntimeInvisibleAnnotations:
- {
- if(!cfs.skip(attr_len)) {
- REPORT_FAILED_CLASS_FORMAT(_class,
- "failed to skip RuntimeInvisibleAnnotations attribute");
- return ATTR_ERROR;
- }
- }
- break;
-
- default:
- return ATTR_UNDEF;
- }
- return attr;
-}
-
void* Class_Member::Alloc(size_t size) {
ClassLoader* cl = get_class()->get_class_loader();
assert(cl);
@@ -621,12 +557,15 @@
}
_class = clss;
+
+ //See specification 4.6 about name_index
uint16 name_index;
if (!cfs.parse_u2_be(&name_index)) {
REPORT_FAILED_CLASS_FORMAT(clss, "cannot parse member name index");
return false;
}
+ //See specification 4.6 about descriptor_index
uint16 descriptor_index;
if (!cfs.parse_u2_be(&descriptor_index)) {
REPORT_FAILED_CLASS_FORMAT(clss, "cannot parse member descriptor index");
@@ -635,17 +574,18 @@
ConstantPool& cp = clss->get_constant_pool();
//
- // look up the name_index and descriptor_index
- // utf8 string const pool entries
+ // Look up the name_index and descriptor_index
+ // utf8 string const pool entries.
+ // See specification 4.6 about name_index and desctiptor_index.
//
String* name = cp_check_utf8(cp, name_index);
String* descriptor = cp_check_utf8(cp, descriptor_index);
if (name == NULL || descriptor == NULL) {
- REPORT_FAILED_CLASS_FORMAT(clss,
- "some of member name or descriptor indexes is not CONSTANT_Utf8 entry : "
+ REPORT_FAILED_CLASS_FORMAT(clss,
+ "some of member name or descriptor indexes is not CONSTANT_Utf8 entry : "
<< name_index << " or " << descriptor_index);
return false;
- }
+ }
_name = name;
_descriptor = descriptor;
return true;
@@ -656,11 +596,11 @@
// further constrained so that, with the exception of the special method names (§3.9)
// and , they must not contain the characters ’<’ or ’>’.
static inline bool
-check_field_name(const String *name)
+check_field_name(const char *name, unsigned len)
{
- for (const char* ch = name->bytes; ch[0] != '\0'; ++ch) {
- switch(ch[0]){
- case '.':
+ for (unsigned i = 0; i < len; i++) {
+ switch(name[i]){
+ case '.':
case ';':
case '[':
case '/':
@@ -671,14 +611,11 @@
}
static inline bool
-check_method_name(const String *name, const Global_Env& env)
+check_method_name(const char *name, unsigned len)
{
- if (name == env.Init_String || name == env.Clinit_String)
- return true;
-
- for (const char* ch = name->bytes; ch[0] != '\0'; ++ch) {
- switch(ch[0]){
- case '.':
+ for (unsigned i = 0; i < len; i++) {
+ switch(name[i]){
+ case '.':
case ';':
case '[':
case '/':
@@ -695,7 +632,7 @@
const char **next,
bool is_void_legal)
{
- switch (*descriptor)
+ switch (*descriptor)
{
case 'B':
case 'C':
@@ -716,19 +653,35 @@
}
case 'L':
{
- const char* iterator = descriptor + 1;
- while( *iterator != ';' ) {
- iterator++;
+ unsigned id_len = 0;
+ //See specification 4.4.2 about field descriptors that
+ //classname represents a fully qualified class or interface name in internal form.
+ const char* iterator;
+ for(iterator = ++descriptor;
+ *iterator != ';';
+ iterator++)
+ {
if( *iterator == '\0' ) {
// bad Java descriptor
return false;
}
+ if(*iterator == '/') {
+ if(!check_field_name(descriptor, id_len))
+ return false;
+ id_len = 0;
+ descriptor = iterator + 1;
+ } else {
+ id_len++;
+ }
}
+ if(!check_field_name(descriptor, id_len))
+ return false;
*next = iterator + 1;
return true;
}
case '[':
{
+ //See specification 4.4.2 or 4.5.1 about array type descriptor
unsigned dim = 1;
while(*(++descriptor) == '[') dim++;
if (dim > 255) return false;
@@ -748,19 +701,23 @@
if(!Class_Member::parse(clss, cfs))
return false;
- if(!check_field_name(_name)) {
+ if(!check_field_name(_name->bytes, _name->len)) {
REPORT_FAILED_CLASS_FORMAT(clss, "illegal field name : " << _name->bytes);
return false;
}
// check field descriptor
+ //See specification 4.4.2 about field descriptors.
const char* next;
if(!check_field_descriptor(_descriptor->bytes, &next, false) || *next != '\0') {
REPORT_FAILED_CLASS_FORMAT(clss, "illegal field descriptor : " << _descriptor->bytes);
return false;
}
- // check interface fields access flags
+
+ // check fields access flags
+ //See specification 4.6 about access flags
if( clss->is_interface() ) {
+ // check interface fields access flags
if(!(is_public() && is_static() && is_final())){
REPORT_FAILED_CLASS_FORMAT(clss, "interface field " << get_name()->bytes
<< " does not have one of ACC_PUBLIC, ACC_STATIC, or ACC_FINAL access flags set");
@@ -771,15 +728,16 @@
<< " has illegal access flags set : " << _access_flags); //FIXME to literal form
return false;
}
- } else if((is_public() && is_protected()
- || is_protected() && is_private()
+ } else if((is_public() && is_protected()
+ || is_protected() && is_private()
|| is_public() && is_private())
|| (is_final() && is_volatile())) {
- REPORT_FAILED_CLASS_FORMAT(clss, " field " << get_name()->bytes
+ REPORT_FAILED_CLASS_FORMAT(clss, " field " << get_name()->bytes
<< " has invalid combination of access flags : " << _access_flags); //FIXME to literal form
return false;
}
+ //check field attributes
uint16 attr_count;
if(!cfs.parse_u2_be(&attr_count)) {
REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
@@ -789,150 +747,232 @@
_offset_computed = 0;
- unsigned n_constval_attr = 0;
-
+ unsigned numConstantValue = 0;
+ unsigned numRuntimeVisibleAnnotations = 0;
+ unsigned numRuntimeInvisibleAnnotations = 0;
uint32 attr_len = 0;
ConstantPool& cp = clss->get_constant_pool();
- for (unsigned j=0; j 1) {
+ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
+ clss->get_name()->bytes << ": field " << get_name() << " has more then one ConstantValue attribute");
+ return false;
+ }
+ // attribute length must be two (vm spec reference 4.7.3)
+ if (attr_len != 2) {
+ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
+ clss->get_name()->bytes << ": ConstantValue attribute has invalid length for field " << get_name());
+ return false;
+ }
- // a field can have at most 1 ConstantValue attribute
- if (++n_constval_attr > 1) {
- REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
- clss->get_name()->bytes << ": field " << get_name() << " has more then one ConstantValue attribute");
- return false;
- }
- // attribute length must be two (vm spec reference 4.7.3)
- if (attr_len != 2) {
- REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
- clss->get_name()->bytes << ": ConstantValue attribute has invalid length for field " << get_name());
- return false;
- }
-
- if(!cfs.parse_u2_be(&_const_value_index)) {
- REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss,
- "java/lang/ClassFormatError",
- clss->get_name()->bytes << ": could not parse "
- << "ConstantValue index for field " << get_name());
- return false;
- }
-
- if(_const_value_index == 0 || _const_value_index >= cp.get_size()) {
- REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
- clss->get_name()->bytes << ": invalid ConstantValue index for field " << get_name());
- return false;
- }
-
- Java_Type java_type = get_java_type();
-
- switch(cp.get_tag(_const_value_index)) {
- case CONSTANT_Long:
+ //For non-static field ConstantValue attribute must be silently ignored
+ //See specification 4.8.2, second paragraph
+ if(!is_static())
{
- if (java_type != JAVA_TYPE_LONG) {
- REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
- clss->get_name()->bytes
- << ": data type CONSTANT_Long of ConstantValue does not correspond to the type of field "
- << get_name());
+ if(!cfs.skip(attr_len))
+ {
+ REPORT_FAILED_CLASS_FORMAT(clss,
+ "couldn't skip ConstantValue attribute for field "
+ << _name->bytes);
return false;
}
- const_value.l.lo_bytes = cp.get_8byte_low_word(_const_value_index);
- const_value.l.hi_bytes = cp.get_8byte_high_word(_const_value_index);
- break;
}
- case CONSTANT_Float:
+ else
{
- if (java_type != JAVA_TYPE_FLOAT) {
- REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
- clss->get_name()->bytes
- << ": data type CONSTANT_Float of ConstantValue does not correspond to the type of field "
- << get_name());
+ if(!cfs.parse_u2_be(&_const_value_index)) {
+ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss,
+ "java/lang/ClassFormatError",
+ clss->get_name()->bytes << ": could not parse "
+ << "ConstantValue index for field " << get_name());
return false;
}
- const_value.f = cp.get_float(_const_value_index);
- break;
- }
- case CONSTANT_Double:
- {
- if (java_type != JAVA_TYPE_DOUBLE) {
+
+ if(!cp.is_valid_index(_const_value_index)) {
REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
- clss->get_name()->bytes
- << ": data type CONSTANT_Double of ConstantValue does not correspond to the type of field "
- << get_name());
+ clss->get_name()->bytes << ": invalid ConstantValue index for field " << get_name());
return false;
}
- const_value.l.lo_bytes = cp.get_8byte_low_word(_const_value_index);
- const_value.l.hi_bytes = cp.get_8byte_high_word(_const_value_index);
- break;
+
+ Java_Type java_type = get_java_type();
+
+ switch(cp.get_tag(_const_value_index)) {
+ case CONSTANT_Long:
+ {
+ if (java_type != JAVA_TYPE_LONG) {
+ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
+ clss->get_name()->bytes
+ << ": data type CONSTANT_Long of ConstantValue does not correspond to the type of field "
+ << get_name());
+ return false;
+ }
+ const_value.l.lo_bytes = cp.get_8byte_low_word(_const_value_index);
+ const_value.l.hi_bytes = cp.get_8byte_high_word(_const_value_index);
+ break;
+ }
+ case CONSTANT_Float:
+ {
+ if (java_type != JAVA_TYPE_FLOAT) {
+ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
+ clss->get_name()->bytes
+ << ": data type CONSTANT_Float of ConstantValue does not correspond to the type of field "
+ << get_name());
+ return false;
+ }
+ const_value.f = cp.get_float(_const_value_index);
+ break;
+ }
+ case CONSTANT_Double:
+ {
+ if (java_type != JAVA_TYPE_DOUBLE) {
+ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
+ clss->get_name()->bytes
+ << ": data type CONSTANT_Double of ConstantValue does not correspond to the type of field "
+ << get_name());
+ return false;
+ }
+ const_value.l.lo_bytes = cp.get_8byte_low_word(_const_value_index);
+ const_value.l.hi_bytes = cp.get_8byte_high_word(_const_value_index);
+ break;
+ }
+ case CONSTANT_Integer:
+ {
+ if ( !(java_type == JAVA_TYPE_INT ||
+ java_type == JAVA_TYPE_SHORT ||
+ java_type == JAVA_TYPE_BOOLEAN ||
+ java_type == JAVA_TYPE_BYTE ||
+ java_type == JAVA_TYPE_CHAR) )
+ {
+ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
+ clss->get_name()->bytes
+ << ": data type CONSTANT_Integer of ConstantValue does not correspond to the type of field "
+ << get_name());
+ return false;
+ }
+ const_value.i = cp.get_int(_const_value_index);
+ break;
+ }
+ case CONSTANT_String:
+ {
+ if (java_type != JAVA_TYPE_CLASS) {
+ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss,
+ "java/lang/ClassFormatError",
+ clss->get_name()->bytes
+ << ": data type " << "CONSTANT_String of "
+ << "ConstantValue does not correspond "
+ << "to the type of field " << get_name());
+ return false;
+ }
+ const_value.string = cp.get_string(_const_value_index);
+ break;
+ }
+ default:
+ {
+ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss,
+ "java/lang/ClassFormatError",
+ clss->get_name()->bytes
+ << ": invalid data type tag of ConstantValue "
+ << "for field " << get_name());
+ return false;
+ }
+ }//switch
+ }//else for static field
+ }//case ATTR_ConstanValue
+ break;
+
+ case ATTR_Synthetic:
+ {
+ if(attr_len != 0) {
+ REPORT_FAILED_CLASS_FORMAT(clss,
+ "attribute Synthetic has non-zero length");
+ return false;
}
- case CONSTANT_Integer:
- {
- if ( !(java_type == JAVA_TYPE_INT ||
- java_type == JAVA_TYPE_SHORT ||
- java_type == JAVA_TYPE_BOOLEAN ||
- java_type == JAVA_TYPE_BYTE ||
- java_type == JAVA_TYPE_CHAR) )
- {
- REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
- clss->get_name()->bytes
- << ": data type CONSTANT_Integer of ConstantValue does not correspond to the type of field "
- << get_name());
- return false;
- }
- const_value.i = cp.get_int(_const_value_index);
- break;
+ _access_flags |= ACC_SYNTHETIC;
+ }
+ break;
+
+ case ATTR_Deprecated:
+ {
+ if(attr_len != 0) {
+ REPORT_FAILED_CLASS_FORMAT(clss,
+ "attribute Deprecated has non-zero length");
+ return false;
}
- case CONSTANT_String:
- {
- if (java_type != JAVA_TYPE_CLASS) {
- REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss,
- "java/lang/ClassFormatError",
- clss->get_name()->bytes
- << ": data type " << "CONSTANT_String of "
- << "ConstantValue does not correspond "
- << "to the type of field " << get_name());
- return false;
- }
- const_value.string = cp.get_string(_const_value_index);
- break;
+ _deprecated = true;
+ }
+ break;
+
+ case ATTR_Signature:
+ {
+ if(_signature != NULL) {
+ REPORT_FAILED_CLASS_FORMAT(clss,
+ "more than one Signature attribute for the class");
+ return false;
}
- default:
- {
- REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss,
- "java/lang/ClassFormatError",
- clss->get_name()->bytes
- << ": invalid data type tag of ConstantValue "
- << "for field " << get_name());
+ if (!(_signature = parse_signature_attr(cfs, attr_len, clss))) {
return false;
}
}
break;
- }
+ case ATTR_RuntimeVisibleAnnotations:
+ {
+ // Each field_info structure may contain at most one RuntimeVisibleAnnotations attribute.
+ // See specification 4.8.14.
+ if(++numRuntimeVisibleAnnotations > 1) {
+ REPORT_FAILED_CLASS_FORMAT(clss,
+ "more than one RuntimeVisibleAnnotations attribute");
+ return false;
+ }
+
+ uint32 read_len = parse_annotation_table(&_annotations, cfs, clss);
+ if (attr_len != read_len) {
+ REPORT_FAILED_CLASS_FORMAT(clss,
+ "error parsing Annotations attribute"
+ << "; declared length " << attr_len
+ << " does not match actual " << read_len);
+ return false;
+ }
+ }
+ break;
+
+ case ATTR_RuntimeInvisibleAnnotations:
+ {
+ if(++numRuntimeInvisibleAnnotations > 1) {
+ REPORT_FAILED_CLASS_FORMAT(clss,
+ "more than one RuntimeVisibleAnnotations attribute");
+ return false;
+ }
+ if(!cfs.skip(attr_len)) {
+ REPORT_FAILED_CLASS_FORMAT(clss,
+ "failed to skip RuntimeInvisibleAnnotations attribute");
+ return false;
+ }
+ }
+ break;
+
case ATTR_UNDEF:
// unrecognized attribute; skipped
break;
+ case ATTR_ERROR:
+ return false;
default:
- switch(process_common_attribute(cur_attr, attr_len, cfs)) {
- case ATTR_ERROR:
- // tried and failed
- return false;
- case ATTR_UNDEF:
- // unprocessed
- REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/InternalError",
- clss->get_name()->bytes
- << ": error parsing attributes for field "
- << get_name()->bytes
- << "; unprocessed attribute " << cur_attr);
- return false;
- } // switch
+ REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/InternalError",
+ _class->get_name()->bytes << ": unknown error occured "
+ "while parsing attributes for field "
+ << _name->bytes << _descriptor->bytes
+ << "; unprocessed attribute " << cur_attr);
+ return false;
+ break;
} // switch
} // for
@@ -954,6 +994,7 @@
bool Handler::parse(ConstantPool& cp, unsigned code_length,
ByteReader& cfs)
{
+ //See specification 4.8.3 about exception_table
uint16 start = 0;
if(!cfs.parse_u2_be(&start))
return false;
@@ -1009,8 +1050,8 @@
}
}
-bool Method::get_local_var_entry(unsigned index, jlong* pc,
- jint* length, jint* slot, String** name,
+bool Method::get_local_var_entry(unsigned index, jlong* pc,
+ jint* length, jint* slot, String** name,
String** type, String** generic_type) {
if (_line_number_table && index < _local_vars_table->length) {
@@ -1043,6 +1084,7 @@
}
_exceptions = new String*[_n_exceptions];
+ //FIXME: verav Should throw OOM
for (unsigned i=0; i<_n_exceptions; i++) {
uint16 index;
if(!cfs.parse_u2_be(&index)) {
@@ -1053,6 +1095,7 @@
return false;
}
+ //See specification 4.8.4 about exception_index_table[].
_exceptions[i] = cp_check_class(cp, index);
if (_exceptions[i] == NULL) {
REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
@@ -1080,14 +1123,14 @@
"while parsing LineNumberTable attribute");
return false;
}
- unsigned real_lnt_attr_len = 2 + n_line_numbers * 4;
+ //See specification 4.8.10 about attribute_length.
+ unsigned real_lnt_attr_len = 2 + n_line_numbers * 4;
if(real_lnt_attr_len != attr_len) {
- REPORT_FAILED_METHOD("real LineNumberTable length differ "
- "from attribute_length ("
+ REPORT_FAILED_METHOD("LineNumberTable attribute has wrong length ("
<< attr_len << " vs. " << real_lnt_attr_len << ")" );
return false;
}
-
+
_line_number_table =
(Line_Number_Table *)STD_MALLOC(sizeof(Line_Number_Table) +
sizeof(Line_Number_Entry) * (n_line_numbers - 1));
@@ -1122,41 +1165,24 @@
} //Method::_parse_line_numbers
-bool Method::_parse_local_vars(const char* attr_name, Local_Var_Table** lvt_address,
- ConstantPool& cp, unsigned attr_len, ByteReader &cfs)
+bool Method::_parse_local_vars(Local_Var_Table* table, LocalVarOffset *offset_list,
+ ConstantPool& cp, ByteReader &cfs, const char *attr_name, Attributes attribute)
{
- uint16 n_local_vars;
- if(!cfs.parse_u2_be(&n_local_vars)) {
- REPORT_FAILED_METHOD("could not parse local variables number "
- "of " << attr_name << " attribute");
- return false;
- }
- unsigned real_lnt_attr_len = 2 + n_local_vars * 10;
- if(real_lnt_attr_len != attr_len) {
- REPORT_FAILED_METHOD("real " << attr_name << " length differ "
- "from declared length ("
- << attr_len << " vs. " << real_lnt_attr_len << ")" );
- return false;
- }
- if (!n_local_vars) {
- return true;
- }
+ for (unsigned j = 0; j < table->length; j++) {
+ //go to the start of entry
+ if(!cfs.go_to_offset(offset_list->value)){
+ return false;
+ }
- Local_Var_Table* table = (Local_Var_Table *)_class->get_class_loader()->Alloc(
- sizeof(Local_Var_Table) +
- sizeof(Local_Var_Entry) * (n_local_vars - 1));
- // ppervov: FIXME: should throw OOME
- table->length = n_local_vars;
-
- for (unsigned j = 0; j < n_local_vars; j++) {
- uint16 start_pc;
+ uint16 start_pc;
if(!cfs.parse_u2_be(&start_pc)) {
REPORT_FAILED_METHOD("could not parse start_pc "
"in " << attr_name << " attribute");
return false;
}
- uint16 length;
+
+ uint16 length;
if(!cfs.parse_u2_be(&length)) {
REPORT_FAILED_METHOD("could not parse length entry "
"in " << attr_name << " attribute");
@@ -1191,6 +1217,12 @@
return false;
}
+ if(!check_field_name(name->bytes, name->len))
+ {
+ REPORT_FAILED_METHOD("name of local variable: " << name->bytes <<
+ " in " << attr_name << " attribute is not stored as unqualified name");
+ return false;
+ }
String* descriptor = cp_check_utf8(cp, descriptor_index);
if(descriptor == NULL) {
REPORT_FAILED_METHOD("descriptor index is not valid CONSTANT_Utf8 entry "
@@ -1198,6 +1230,17 @@
return false;
}
+ if(attribute == ATTR_LocalVariableTable)
+ {
+ const char *next;
+ if(!check_field_descriptor(descriptor->bytes, &next, false) || *next != '\0')
+ {
+ REPORT_FAILED_METHOD("illegal field descriptor: " << descriptor->bytes <<
+ " in " << attr_name << " attribute for local variable: " << name->bytes);
+ return false;
+ }
+ }
+
uint16 index;
if(!cfs.parse_u2_be(&index)) {
REPORT_FAILED_METHOD("could not parse index "
@@ -1205,7 +1248,6 @@
return false;
}
- // FIXME Don't work with long and double
if (index >= _max_locals) {
REPORT_FAILED_METHOD("invalid local index "
"in " << attr_name << " attribute");
@@ -1218,10 +1260,26 @@
table->table[j].name = name;
table->table[j].type = descriptor;
table->table[j].generic_type = NULL;
+
+ offset_list = offset_list->next;
}
- assert(lvt_address);
- *lvt_address = table;
+ //checks that there are no same LocalVariableTable or LovalVariableTypeTable attribute in Code
+ //Can't check this in simulated mode
+ for (unsigned j = 0; j < table->length; j++)
+ {
+ for(unsigned i = j + 1; i < table->length; i++)
+ {
+ if(table->table[j].start_pc == table->table[i].start_pc
+ &&table->table[j].length == table->table[i].length
+ &&table->table[j].index == table->table[i].index)
+ {
+ REPORT_FAILED_METHOD("Duplicate attribute "<< attr_name
+ <<" for local variable ");
+ return false;
+ }
+ }
+ }
return true;
} //Method::_parse_local_vars
@@ -1247,7 +1305,8 @@
return false;
}
- if(_max_locals < _arguments_size/4) {
+ //See specification 4.8.3 about Code Attribute, max_locals.
+ if(_max_locals < _arguments_slot_num) {
REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
_class->get_name()->bytes << ": wrong max_locals count "
<< "while parsing Code attribute for method "
@@ -1263,16 +1322,19 @@
return false;
}
+ // See specification 4.8.3 and 4.10.1 about code_length.
// code length for non-abstract java methods must not be 0
if(_byte_code_length == 0
- || (_byte_code_length >= (1<<16) && !is_native() && !is_abstract()))
+ || (_byte_code_length >= (1<<16)))
{
REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
_class->get_name()->bytes << ": bytecode length for method "
<< _name->bytes << _descriptor->bytes
- << " has zero length");
+ << " has zero or exceeding length");
return false;
}
+
+ //See specification 4.8.3 about attribute_length value.
real_code_attr_len = 8;
//
@@ -1300,7 +1362,7 @@
}
real_code_attr_len += 2;
- //
+ //
// allocate & parse exception handler table
//
_handlers = new Handler[_n_handlers];
@@ -1314,7 +1376,7 @@
return false;
}
}
- real_code_attr_len += _n_handlers*8; // for the size of exception_table entry see JVM Spec 4.7.3
+ real_code_attr_len += _n_handlers*8; // for the size of exception_table entry see JVM Spec 4.8.3
//
// attributes of the Code attribute
@@ -1329,11 +1391,17 @@
real_code_attr_len += 2;
static bool TI_enabled = VM_Global_State::loader_env->TI->isEnabled();
- Local_Var_Table * generic_vars = NULL;
uint32 attr_len = 0;
+ LocalVarOffset* offset_lvt_array = NULL;
+ LocalVarOffset* lvt_iter = NULL;
+ LocalVarOffset* offset_lvtt_array = NULL;
+ LocalVarOffset* lvtt_iter = NULL;
+ unsigned num_lvt_entries = 0;
+ unsigned num_lvtt_entries = 0;
+
for (i=0; inext = (LocalVarOffset*)STD_ALLOCA(sizeof(LocalVarOffset) * n_local_vars);
+ lvt_iter = lvt_iter->next;
}
- else if (!cfs.skip(attr_len))
+ int off = cfs.get_offset();
+
+ int j = 0;
+ for(j = 0; j < n_local_vars - 1; j++, lvt_iter++)
{
- REPORT_FAILED_METHOD("error skipping Local_Variable_Table");
+ lvt_iter->value = off + 10*j;
+ lvt_iter->next = lvt_iter + 1;
}
+ lvt_iter->value = off + 10*j;
+ lvt_iter->next = NULL;
+ num_lvt_entries += n_local_vars;
+ if (!cfs.skip(10*n_local_vars))
+ {
+ REPORT_FAILED_METHOD("error skipping");
+ return false;
+ }
break;
}
case ATTR_LocalVariableTypeTable:
{
- if (TI_enabled)
+ uint16 n_local_vars;
+ if(!cfs.parse_u2_be(&n_local_vars)) {
+ REPORT_FAILED_METHOD("could not parse local variables number "
+ "of LocalVariableTypeTable attribute");
+ return false;
+ }
+ unsigned lnt_attr_len = 2 + n_local_vars * 10;
+ if(lnt_attr_len != attr_len) {
+ REPORT_FAILED_METHOD("real LocalVariableTypeTable attribute length differ "
+ "from declared length ("
+ << attr_len << " vs. " << lnt_attr_len << ")" );
+ return false;
+ }
+ if(n_local_vars == 0) continue;
+
+ if(offset_lvtt_array == NULL){
+ offset_lvtt_array = lvtt_iter =
+ (LocalVarOffset*)STD_ALLOCA(sizeof(LocalVarOffset) * n_local_vars);
+ }
+ else
{
- if (!_parse_local_vars("LocalVariableTypeTable", &generic_vars, cp, attr_len, cfs))
- {
- return false;
- }
+ lvtt_iter->next = (LocalVarOffset*)STD_ALLOCA(sizeof(LocalVarOffset) * n_local_vars);
+ lvtt_iter = lvtt_iter->next;
}
- else if (!cfs.skip(attr_len))
+ int off = cfs.get_offset();
+ int j = 0;
+ for(j = 0; j < n_local_vars - 1; j++, lvtt_iter++)
{
- REPORT_FAILED_METHOD("error skipping LocalVariableTypeTable");
+ lvtt_iter->value = off + 10*j;
+ lvtt_iter->next = lvtt_iter + 1;
}
+ lvtt_iter->value = off + 10*j;
+ lvtt_iter->next = NULL;
+ num_lvtt_entries += n_local_vars;
+
+ if (!cfs.skip(10*n_local_vars))
+ {
+ REPORT_FAILED_METHOD("error skipping");
+ return false;
+ }
+ break;
}
- break;
-
case ATTR_UNDEF:
// unrecognized attribute; skipped
break;
+ case ATTR_ERROR:
+ return false;
default:
// error occured
REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/InternalError",
@@ -1388,6 +1517,81 @@
real_code_attr_len += 6 + attr_len; // u2 - attribute_name_index, u4 - attribute_length
} // for
+ // we should remember this point to return here
+ // after comlete LVT and LVTT parsing.
+ int return_point = cfs.get_offset();
+
+ //lvt and lvtt parsing
+ Local_Var_Table* lv_table = NULL;
+ Local_Var_Table* generic_vars = NULL;
+ static const int LV_ALLOCATION_THRESHOLD = 30;
+
+ if( num_lvtt_entries < LV_ALLOCATION_THRESHOLD ){
+ generic_vars = (Local_Var_Table *)STD_ALLOCA(sizeof(Local_Var_Table) +
+ sizeof(Local_Var_Entry) * (num_lvtt_entries - 1));
+ } else {
+ generic_vars = (Local_Var_Table *)STD_MALLOC(sizeof(Local_Var_Table) +
+ sizeof(Local_Var_Entry) * (num_lvtt_entries - 1));
+ }
+ generic_vars->length = num_lvtt_entries;
+
+ if(TI_enabled) {
+ lv_table = (Local_Var_Table *)_class->get_class_loader()->Alloc(
+ sizeof(Local_Var_Table) +
+ sizeof(Local_Var_Entry) * (num_lvt_entries - 1));
+ } else {
+ if( num_lvt_entries < LV_ALLOCATION_THRESHOLD){
+ lv_table =(Local_Var_Table *)STD_ALLOCA(sizeof(Local_Var_Table) +
+ sizeof(Local_Var_Entry) * (num_lvt_entries - 1));
+ } else {
+ lv_table =(Local_Var_Table *)STD_MALLOC(sizeof(Local_Var_Table) +
+ sizeof(Local_Var_Entry) * (num_lvt_entries - 1));
+ }
+ }
+ lv_table->length = num_lvt_entries;
+
+ if (!_parse_local_vars(lv_table, offset_lvt_array, cp, cfs,
+ "LocalVariableTable", ATTR_LocalVariableTable)
+ || !_parse_local_vars(generic_vars, offset_lvtt_array, cp, cfs,
+ "LocalVariableTypeTable", ATTR_LocalVariableTypeTable))
+ {
+ return false;
+ }
+ // JVM spec hints that LocalVariableTypeTable is meant to be a supplement to LocalVariableTable
+ // so we have no reason to cross-check these tables
+ // See specification 4.8.12 second paragraph.
+ if (generic_vars && lv_table) {
+ unsigned j = i = 0;
+ for (i = 0; i < generic_vars->length && j != lv_table->length; i++) {
+ for (j = 0; j < lv_table->length; j++) {
+ if (generic_vars->table[i].name == lv_table->table[j].name
+ && generic_vars->table[i].start_pc == lv_table->table[j].start_pc
+ && generic_vars->table[i].length == lv_table->table[j].length
+ && generic_vars->table[i].index == lv_table->table[j].index)
+ {
+ lv_table->table[j].generic_type = generic_vars->table[i].type;
+ break;
+ }
+ }
+ }
+ String* gvi_name = generic_vars->table[i].name;
+ if( num_lvtt_entries >= LV_ALLOCATION_THRESHOLD ){
+ STD_FREE(generic_vars);
+ }
+ if(j == lv_table->length) {
+ REPORT_FAILED_METHOD("Element: "<< gvi_name <<
+ " from LocalVariableTypeTable doesn't coincide with element from LocalVariableTable");
+ }
+ }
+
+ if(TI_enabled) {
+ _local_vars_table = lv_table;
+ } else {
+ if(num_lvt_entries >= LV_ALLOCATION_THRESHOLD) {
+ STD_FREE(lv_table);
+ }
+ }
+
if(code_attr_len != real_code_attr_len) {
REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
_class->get_name()->bytes << ": Code attribute length does not match real length "
@@ -1397,17 +1601,10 @@
return false;
}
- // JVM spec hints that LocalVariableTypeTable is meant to be a supplement to LocalVariableTable
- // so we have no reason to cross-check these tables
- if (generic_vars && _local_vars_table) {
- unsigned j;
- for (i = 0; i < generic_vars->length; ++i) {
- for (j = 0; j < _local_vars_table->length; ++j) {
- if (generic_vars->table[i].name == _local_vars_table->table[j].name) {
- _local_vars_table->table[j].generic_type = generic_vars->table[i].type;
- }
- }
- }
+ //return to the right ByteReader point
+ if(!cfs.go_to_offset(return_point))
+ {
+ return false;
}
return true;
@@ -1436,16 +1633,19 @@
return result;
}
-
bool Method::parse(Global_Env& env, Class* clss,
ByteReader &cfs)
{
if(!Class_Member::parse(clss, cfs))
return false;
- if(!check_method_name(_name, env)) {
- REPORT_FAILED_CLASS_FORMAT(clss, "illegal method name : " << _name->bytes);
- return false;
+ if(!(_name == env.Init_String || _name == env.Clinit_String))
+ {
+ if(!check_method_name(_name->bytes, _name->len))
+ {
+ REPORT_FAILED_CLASS_FORMAT(clss, "illegal method name : " << _name->bytes);
+ return false;
+ }
}
// check method descriptor
@@ -1456,24 +1656,28 @@
<< _name->bytes << _descriptor->bytes);
return false;
}
- calculate_arguments_size();
+ calculate_arguments_slot_num();
- uint16 attr_count;
- if (!cfs.parse_u2_be(&attr_count)) {
+ //The total length of method parameters should be 255 or less.
+ //See 4.4.3 in specification.
+ if(_arguments_slot_num > 255) {
REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
- _class->get_name()->bytes << ": could not parse attributes count for method "
- << _name->bytes << _descriptor->bytes);
+ _class->get_name()->bytes <<
+ ": method has more than 255 arguments "
+ << _name->bytes );
return false;
}
+ // checked method descriptor
+
_intf_method_for_fake_method = NULL;
// set the has_finalizer, is_clinit and is_init flags
- if (_name == env.FinalizeName_String && _descriptor == env.VoidVoidDescriptor_String) {
+ if(_name == env.FinalizeName_String && _descriptor == env.VoidVoidDescriptor_String) {
_flags.is_finalize = 1;
}
- else if (_name == env.Init_String)
+ else if(_name == env.Init_String)
_flags.is_init = 1;
- else if (_name == env.Clinit_String)
+ else if(_name == env.Clinit_String)
_flags.is_clinit = 1;
// check method access flags
if(!is_clinit())
@@ -1481,6 +1685,7 @@
if(is_private() && is_protected() || is_private() && is_public() || is_protected() && is_public())
{
bool bout = false;
+ //See specification 4.7 Methods about access_flags
REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
_class->get_name()->bytes << ": invalid combination of access flags ("
<< ((bout = is_public())?"ACC_PUBLIC":"")
@@ -1492,7 +1697,7 @@
<< _name->bytes << _descriptor->bytes);
return false;
}
- if(is_abstract()
+ if(is_abstract()
&& (is_final() || is_native() || is_private() || is_static() || is_strict() || is_synchronized()))
{
bool bout = false;
@@ -1513,35 +1718,28 @@
<< _name->bytes << _descriptor->bytes);
return false;
}
- if(_class->is_interface() && !(is_abstract() && is_public())) {
- REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
- _class->get_name()->bytes << "." << _name->bytes << _descriptor->bytes
- << ": interface method cannot have access flags other then "
- "ACC_ABSTRACT and ACC_PUBLIC set"
- );
- return false;
- }
- if(_class->is_interface() &&
- (is_private() || is_protected() || is_static() || is_final()
- || is_synchronized() || is_native() || is_strict()))
+ if(_class->is_interface())
{
- REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
- _class->get_name()->bytes << "." << _name->bytes << _descriptor->bytes
- << ": interface method cannot have access flags other then "
- "ACC_ABSTRACT and ACC_PUBLIC set");
- return false;
+ if(!(is_abstract() && is_public())){
+ REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
+ _class->get_name()->bytes << "." << _name->bytes << _descriptor->bytes
+ << ": interface method must have access flags "
+ "ACC_ABSTRACT and ACC_PUBLIC set"
+ );
+ return false;
+ }
+ if(_access_flags & ~(ACC_ABSTRACT | ACC_PUBLIC | ACC_VARARGS | ACC_BRIDGE | ACC_SYNTHETIC)){
+ REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
+ _class->get_name()->bytes << "." << _name->bytes << _descriptor->bytes
+ << ": interface method cannot have access flags other then "
+ "ACC_ABSTRACT, ACC_PUBLIC, ACC_VARARG, ACC_BRIDGES or ACC_SYNTHETIC set");
+ return false;
+ }
}
- }
- if(is_init() && (is_static() || is_final() || is_synchronized() || is_native() || is_abstract() || is_bridge())) {
- REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
- _class->get_name()->bytes << "." << _name->bytes << _descriptor->bytes
- << ": constructor cannot have access flags other then "
- "ACC_STRICT and one of ACC_PUBLIC, ACC_PRIVATE, or ACC_PROTECTED set");
- return false;
- }
- if(is_clinit()) {
+
+ } else {
// Java VM specification
- // 4.6 Methods
+ // 4.7 Methods
// "Class and interface initialization methods (�3.9) are called
// implicitly by the Java virtual machine; the value of their
// access_flags item is ignored except for the settings of the
@@ -1553,8 +1751,28 @@
_access_flags |= ACC_STATIC;
}
- unsigned n_code_attr = 0;
- unsigned n_exceptions_attr = 0;
+ if(is_init() && (is_static() || is_final() || is_synchronized() || is_native() || is_abstract() || is_bridge())) {
+ REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
+ _class->get_name()->bytes << "." << _name->bytes << _descriptor->bytes
+ << ": constructor cannot have access flags other then "
+ "ACC_STRICT, ACC_VARARGS, ACC_SYNTHETIC and one of ACC_PUBLIC, ACC_PRIVATE, or ACC_PROTECTED set");
+ return false;
+ }
+
+ //check method attributes
+ uint16 attr_count;
+ if(!cfs.parse_u2_be(&attr_count)) {
+ REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
+ _class->get_name()->bytes << ": could not parse attributes count for method "
+ << _name->bytes << _descriptor->bytes);
+ return false;
+ }
+
+ unsigned numCode = 0;
+ unsigned numExceptions = 0;
+ unsigned numRuntimeVisibleAnnotations = 0;
+ unsigned numRuntimeInvisibleAnnotations = 0;
+ unsigned numRuntimeInvisibleParameterAnnotations = 0;
uint32 attr_len = 0;
ConstantPool& cp = clss->get_constant_pool();
@@ -1562,21 +1780,45 @@
//
// only code and exception attributes are defined for Method
//
- Attributes cur_attr = parse_attribute(cfs, cp, method_attr_strings, method_attrs, &attr_len);
+ Attributes cur_attr = parse_attribute(clss, cfs, cp, method_attr_strings, method_attrs, &attr_len);
switch(cur_attr) {
case ATTR_Code:
- n_code_attr++;
+ numCode++;
+ if (numCode > 1) {
+ REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
+ _class->get_name()->bytes << ": there is more than one Code attribute for method "
+ << _name->bytes << _descriptor->bytes);
+ return false;
+ }
+ if((is_abstract() || is_native()) && numCode > 0) {
+ REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
+ _class->get_name()->bytes << "." << _name->bytes << _descriptor->bytes
+ << ": " << (is_abstract()?"abstract":(is_native()?"native":""))
+ << " method should not have Code attribute present");
+ return false;
+ }
if(!_parse_code(cp, attr_len, cfs))
return false;
break;
case ATTR_Exceptions:
- n_exceptions_attr++;
+ if(++numExceptions > 1) {
+ REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
+ _class->get_name()->bytes << ": there is more than one Exceptions attribute for method "
+ << _name->bytes << _descriptor->bytes);
+ return false;
+ }
if(!_parse_exceptions(cp, attr_len, cfs))
return false;
break;
case ATTR_RuntimeInvisibleParameterAnnotations:
+ if(++numRuntimeInvisibleParameterAnnotations > 1) {
+ REPORT_FAILED_CLASS_FORMAT(clss,
+ "more than one RuntimeInvisibleParameterAnnotations attribute");
+ return false;
+ }
+
if (!cfs.skip(attr_len))
{
REPORT_FAILED_METHOD("error skipping RuntimeInvisibleParameterAnnotations");
@@ -1586,6 +1828,7 @@
case ATTR_RuntimeVisibleParameterAnnotations:
{
+ // See specification 4.8.16.
if (_param_annotations) {
REPORT_FAILED_METHOD(
"more than one RuntimeVisibleParameterAnnotations attribute");
@@ -1593,7 +1836,7 @@
}
if (!cfs.parse_u1(&_num_param_annotations)) {
- REPORT_FAILED_CLASS_FORMAT(clss,
+ REPORT_FAILED_CLASS_FORMAT(clss,
"cannot parse number of ParameterAnnotations");
return false;
}
@@ -1601,35 +1844,36 @@
if (_num_param_annotations) {
_param_annotations = (AnnotationTable**)_class->get_class_loader()->Alloc(
_num_param_annotations * sizeof (AnnotationTable*));
-
+ //FIXME: verav should throw OOM
for (unsigned i = 0; i < _num_param_annotations; i++)
{
uint32 next_len = parse_annotation_table(_param_annotations + i, cfs, _class);
if (next_len == 0) {
return false;
- }
+ }
read_len += next_len;
}
}
if (attr_len != read_len) {
- REPORT_FAILED_METHOD(
+ REPORT_FAILED_METHOD(
"error parsing ParameterAnnotations attribute"
<< "; declared length " << attr_len
<< " does not match actual " << read_len);
return false;
- }
+ }
}
break;
case ATTR_AnnotationDefault:
{
+ //See specification 4.8.18 about default_value
if (_default_value) {
REPORT_FAILED_METHOD("more than one AnnotationDefault attribute");
return false;
}
_default_value = (AnnotationValue *)_class->get_class_loader()->Alloc(
sizeof(AnnotationValue));
-
+ //FIXME: verav should throw OOM
uint32 read_len = parse_annotation_value(*_default_value, cfs, clss);
if (read_len == 0) {
return false;
@@ -1643,59 +1887,107 @@
}
break;
+ case ATTR_Synthetic:
+ {
+ if(attr_len != 0) {
+ REPORT_FAILED_CLASS_FORMAT(clss,
+ "attribute Synthetic has non-zero length");
+ return false;
+ }
+ _access_flags |= ACC_SYNTHETIC;
+ }
+ break;
+
+ case ATTR_Deprecated:
+ {
+ if(attr_len != 0) {
+ REPORT_FAILED_CLASS_FORMAT(clss,
+ "attribute Deprecated has non-zero length");
+ return false;
+ }
+ _deprecated = true;
+ }
+ break;
+
+ case ATTR_Signature:
+ {
+ if(_signature != NULL) {
+ REPORT_FAILED_CLASS_FORMAT(clss,
+ "more than one Signature attribute for the class");
+ return false;
+ }
+ if (!(_signature = parse_signature_attr(cfs, attr_len, clss))) {
+ return false;
+ }
+ }
+ break;
+
+ case ATTR_RuntimeVisibleAnnotations:
+ {
+ //Each method_info structure may contain at most one RuntimeVisibleAnnotations attribute.
+ // See specification 4.8.14.
+ if(++numRuntimeVisibleAnnotations > 1) {
+ REPORT_FAILED_CLASS_FORMAT(clss,
+ "more than one RuntimeVisibleAnnotations attribute");
+ return false;
+ }
+
+ uint32 read_len = parse_annotation_table(&_annotations, cfs, clss);
+ if (attr_len != read_len) {
+ REPORT_FAILED_CLASS_FORMAT(clss,
+ "error parsing Annotations attribute"
+ << "; declared length " << attr_len
+ << " does not match actual " << read_len);
+ return false;
+ }
+ }
+ break;
+
+ case ATTR_RuntimeInvisibleAnnotations:
+ {
+ //Each method_info structure may contain at most one RuntimeInvisibleAnnotations attribute.
+ if(++numRuntimeInvisibleAnnotations > 1) {
+ REPORT_FAILED_CLASS_FORMAT(clss,
+ "more than one RuntimeInvisibleAnnotations attribute");
+ return false;
+ }
+
+ if(!cfs.skip(attr_len)) {
+ REPORT_FAILED_CLASS_FORMAT(clss,
+ "failed to skip RuntimeInvisibleAnnotations attribute");
+ return false;
+ }
+ }
+ break;
+
case ATTR_UNDEF:
// unrecognized attribute; skipped
break;
-
+ case ATTR_ERROR:
+ return false;
default:
- switch(process_common_attribute(cur_attr, attr_len, cfs)) {
- case ATTR_ERROR:
- // tried and failed
- return false;
- case ATTR_UNDEF:
- // unprocessed
- REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/InternalError",
- clss->get_name()->bytes
- << " : error parsing attributes for method "
- << _name->bytes << _descriptor->bytes
- << "; unprocessed attribute " << cur_attr);
- return false;
- } // switch
+ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), _class, "java/lang/InternalError",
+ _class->get_name()->bytes << ": unknown error occured "
+ "while parsing attributes for method "
+ << _name->bytes << _descriptor->bytes
+ << "; unprocessed attribute " << cur_attr);
+ return false;
} // switch
} // for
//
// there must be no more than 1 code attribute and no more than 1 exceptions
// attribute per method
+ // See specificaton 4.8.3 and 4.8.4 first paragraphs.
//
- if (n_code_attr > 1) {
- REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
- _class->get_name()->bytes << ": there is more than one Code attribute for method "
- << _name->bytes << _descriptor->bytes);
- return false;
- }
- if(n_exceptions_attr > 1) {
- REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
- _class->get_name()->bytes << ": there is more than one Exceptions attribute for method "
- << _name->bytes << _descriptor->bytes);
- return false;
- }
- if((is_abstract() || is_native()) && n_code_attr > 0) {
- REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
- _class->get_name()->bytes << "." << _name->bytes << _descriptor->bytes
- << ": " << (is_abstract()?"abstract":(is_native()?"native":""))
- << " method should not have Code attribute present");
- return false;
- }
- if(!(is_abstract() || is_native()) && n_code_attr == 0) {
+ if(!(is_abstract() || is_native()) && numCode == 0) {
REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError",
_class->get_name()->bytes << "." << _name->bytes << _descriptor->bytes
<< ": Java method should have Code attribute present");
return false;
}
- if(is_native()) _access_flags |= ACC_NATIVE;
return true;
} //Method::parse
@@ -1753,6 +2045,21 @@
}
assert(last_nonstatic_field == m_num_static_fields);
+ //See specification 4.6 Fields:
+ //No two fields in one class file may have the same name and descriptor.
+ for (int j = 0; j < num_fields_in_class_file; j++){
+ for(int k = j + 1; k < num_fields_in_class_file; k++){
+ if((m_fields[j].get_name() == m_fields[k].get_name())
+ && (m_fields[j].get_descriptor() == m_fields[k].get_descriptor()))
+ {
+ REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/ClassFormatError",
+ "duplicate field " << get_name()->bytes << "."
+ << m_fields[j].get_name()->bytes << " " << m_fields[j].get_descriptor()->bytes);
+ return false;
+ }
+ }
+ }
+
for(i = 0; i < int(sizeof(vm_extra_fields)/sizeof(VMExtraFieldDescription)); i++) {
if(get_name() == vm_extra_fields[i].classname) {
Field& f = m_fields[num_fields_in_class_file];
@@ -1786,8 +2093,10 @@
}
m_methods = new Method[m_num_methods];
+ //FIXME: should throw OOME
_total_method_bytes += sizeof(Method)*m_num_methods;
+
for(unsigned i = 0; i < m_num_methods; i++) {
if(!m_methods[i].parse(*env, this, cfs)) {
return false;
@@ -1803,16 +2112,65 @@
}
m_static_initializer = &(m_methods[i]);
}
- // to cache the default constructor
+ // to cache the default constructor
if (m->get_name() == VM_Global_State::loader_env->Init_String
&& m->get_descriptor() == VM_Global_State::loader_env->VoidVoidDescriptor_String)
{
m_default_constructor = &m_methods[i];
}
}
+
+ //See specification 4.7 Methods:
+ //No two methods in one class file may have the same name and descriptor.
+ for (int j = 0; j < m_num_methods; j++){
+ for(int k = j + 1; k < m_num_methods; k++){
+ if((m_methods[j].get_name() == m_methods[k].get_name())
+ && (m_methods[j].get_descriptor() == m_methods[k].get_descriptor()))
+ {
+ REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/ClassFormatError",
+ "duplicate method " << get_name()->bytes << "."
+ << m_methods[j].get_name()->bytes << m_methods[j].get_descriptor()->bytes);
+ return false;
+ }
+ }
+ }
+
return true; // success
} //class_parse_methods
+static inline bool
+check_class_name(const char *name, unsigned len)
+{
+ unsigned id_len = 0;
+ const char* iterator = name;
+ if(name[0] == '[')
+ {
+ const char *next = name + 1;
+ if(!check_field_descriptor(name, &next, false) || *next != '\0') {
+ return false;
+ }else {
+ return true;
+ }
+ }
+ else
+ {
+ for( unsigned i = 0; i < len ; i++, iterator++ )
+ {
+ if( *iterator != '/' ) {
+ id_len++;
+ }else
+ {
+ if(!check_field_name(name, id_len))
+ return false;
+ id_len = 0;
+ name = iterator;
+ name++;
+ }
+ }
+ return check_field_name(name, id_len);
+ }
+ return false; //unreacheable code
+}
static String* class_file_parse_utf8data(String_Pool& string_pool, ByteReader& cfs,
uint16 len)
@@ -1823,7 +2181,7 @@
// get utf8 bytes and move buffer pointer
const char* utf8data = (const char*)cfs.get_and_skip(len);
-
+
// FIXME: decode 6-byte Java 1.5 encoding
// check utf8 correctness
@@ -1863,6 +2221,7 @@
//
// 0'th constant pool entry is a pointer to the tags array
+ // See specification 4.5 about Constant Pool
//
m_entries[0].tags = cp_tags;
cp_tags[0] = CONSTANT_Tags;
@@ -1976,10 +2335,12 @@
} // ConstantPool::parse
-bool ConstantPool::check(Class* clss)
+bool ConstantPool::check(Global_Env* env, Class* clss)
{
+
+
for(unsigned i = 1; i < m_size; i++) {
- switch(get_tag(i))
+ switch(unsigned char tag = get_tag(i))
{
case CONSTANT_Class:
{
@@ -1990,6 +2351,12 @@
clss->get_name()->bytes << ": wrong name index for CONSTANT_Class entry");
return false;
}
+ if(!check_class_name(get_utf8_string(name_index)->bytes, get_utf8_string(name_index)->len))
+ {
+ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
+ clss->get_name()->bytes << ": illegal CONSTANT_Class name "<< get_utf8_string(name_index)->bytes);
+ return false;
+ }
break;
}
case CONSTANT_Methodref:
@@ -1998,6 +2365,11 @@
{
unsigned class_index = get_ref_class_index(i);
unsigned name_type_index = get_ref_name_and_type_index(i);
+ const char *next = NULL;
+ String *name;
+ String *descriptor;
+ unsigned name_index = get_name_and_type_name_index(name_type_index);
+ unsigned descriptor_index = get_name_and_type_descriptor_index(name_type_index);
if (!is_valid_index(class_index) || !is_class(class_index)) {
REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
clss->get_name()->bytes << ": wrong class index for CONSTANT_*ref entry");
@@ -2008,6 +2380,88 @@
clss->get_name()->bytes << ": wrong name-and-type index for CONSTANT_*ref entry");
return false;
}
+ if(!is_valid_index(name_index) || !is_utf8(name_index)) {
+ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
+ clss->get_name()->bytes << ": wrong name index for CONSTANT_Methodref entry");
+ return false;
+ }
+ if (!is_valid_index(descriptor_index) || !is_utf8(descriptor_index)) {
+ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
+ clss->get_name()->bytes << ": wrong descriptor index for CONSTANT_Methodref entry");
+ return false;
+ }
+
+ name = get_utf8_string(name_index);
+ descriptor = get_utf8_string(descriptor_index);
+
+ if(tag == CONSTANT_Methodref)
+ {
+ //check method name
+ if(name != env->Init_String)
+ {
+ if(!check_method_name(name->bytes,name->len))
+ {
+ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
+ clss->get_name()->bytes << ": illegal method name for CONSTANT_Methodref entry: " << name->bytes);
+ return false;
+ }
+ }
+ //check method descriptor
+ if(!check_method_descriptor(descriptor->bytes))
+ {
+ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
+ clss->get_name()->bytes << ": illegal method descriptor at CONSTANT_Methodref entry: "
+ << descriptor->bytes);
+ return false;
+ }
+ //for method return type must be void
+ //See specification 4.5.2
+ if(name == env->Init_String)
+ {
+ if(descriptor->bytes[descriptor->len - 1] != 'V')
+ {
+ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
+ clss->get_name()->bytes << " return type of method"
+ " is not void at CONSTANT_Methodref entry");
+ return false;
+ }
+ }
+ }
+ if(tag == CONSTANT_Fieldref)
+ {
+ //check field name
+ if(!check_field_name(name->bytes, name->len))
+ {
+ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
+ clss->get_name()->bytes << ": illegal filed name for CONSTANT_Filedref entry: " << name->bytes);
+ return false;
+ }
+ //check field descriptor
+ if(!check_field_descriptor(descriptor->bytes, &next, false) || *next != '\0' )
+ {
+ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
+ clss->get_name()->bytes << ": illegal field descriptor at CONSTANT_Fieldref entry: " << descriptor->bytes);
+ return false;
+ }
+ }
+ if(tag == CONSTANT_InterfaceMethodref)
+ {
+ //check method name, name can't be or
+ //See specification 4.5.2 about name_and_type_index last sentence.
+ if(!check_method_name(name->bytes, name->len))
+ {
+ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
+ clss->get_name()->bytes << ": illegal filed name for CONSTANT_InterfaceMethod entry: " << name->bytes);
+ return false;
+ }
+ //check method descriptor
+ if(!check_method_descriptor(descriptor->bytes))
+ {
+ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
+ clss->get_name()->bytes << ": illegal method descriptor at CONSTANT_InterfaceMethodref entry: " << descriptor->bytes);
+ return false;
+ }
+ }
break;
}
case CONSTANT_String:
@@ -2024,13 +2478,22 @@
break;
}
case CONSTANT_Integer:
- case CONSTANT_Long:
case CONSTANT_Float:
- case CONSTANT_Double:
// not much to do here
break;
+ case CONSTANT_Long:
+ case CONSTANT_Double:
+ //check Long and Double indexes, n+1 index should be valid too.
+ //See specification 4.5.5
+ if( i + 1 > m_size){
+ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
+ clss->get_name()->bytes << ": illegal indexes for Long or Double " << i << " and " << i + 1);
+ return false;
+ }
+ break;
case CONSTANT_NameAndType:
{
+ //See specification 4.5.6
unsigned name_index = get_name_and_type_name_index(i);
unsigned descriptor_index = get_name_and_type_descriptor_index(i);
if(!is_valid_index(name_index) || !is_utf8(name_index)) {
@@ -2038,11 +2501,13 @@
clss->get_name()->bytes << ": wrong name index for CONSTANT_NameAndType entry");
return false;
}
+
if (!is_valid_index(descriptor_index) || !is_utf8(descriptor_index)) {
REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError",
clss->get_name()->bytes << ": wrong descriptor index for CONSTANT_NameAndType entry");
return false;
}
+
resolve_entry(i, get_utf8_string(name_index), get_utf8_string(descriptor_index));
break;
}
@@ -2078,8 +2543,8 @@
return false;
}
//
- // verify that entry in constant pool is of type CONSTANT_Class
- //
+ //Verify that interface index is valid and entry in constant pool is of type CONSTANT_Class
+ //See specification 4.2 about interfaces.
m_superinterfaces[i].name = cp_check_class(m_const_pool, interface_index);
if(m_superinterfaces[i].name == NULL) {
REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/ClassFormatError",
@@ -2105,7 +2570,7 @@
/*
* Parses and verifies the classfile. Format is (from JVM spec):
- *
+ *
* ClassFile {
* u4 magic;
* u2 minor_version;
@@ -2138,6 +2603,7 @@
return false;
}
+ //See 4.2 in specification about value of magic number
if (magic != CLASSFILE_MAGIC) {
REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/ClassFormatError",
"invalid magic");
@@ -2147,6 +2613,7 @@
/*
* get and check major/minor version of classfile
* 1.1 (45.0-3) 1.2 (46.???) 1.3 (47.???) 1.4 (48.?) 5 (49.0)
+ * See 4.2 in specification about minor_version, major_version of classfile.
*/
uint16 minor_version;
if (!cfs.parse_u2_be(&minor_version)) {
@@ -2161,6 +2628,7 @@
return false;
}
+ //See comment in specification 4.2 about supported versions.
if (!(m_version >= CLASSFILE_MAJOR
&& m_version <= CLASSFILE_MAJOR_MAX))
{
@@ -2169,6 +2637,12 @@
return false;
}
+ if(m_version == 49 && minor_version > 0)
+ {
+ REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/UnsupportedClassVersionError",
+ "unsupported class file version " << m_version << "." << minor_version);
+ return false;
+ }
/*
* allocate and parse constant pool
*/
@@ -2178,24 +2652,62 @@
/*
* check and preprocess the constant pool
*/
- if(!m_const_pool.check(this))
+ if(!m_const_pool.check(env, this))
return false;
+ /*
+ * parse access flags
+ */
if(!cfs.parse_u2_be(&m_access_flags)) {
REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/ClassFormatError",
m_name->bytes << ": could not parse access flags");
return false;
}
+ //If class is interface, it must be abstract.
+ //See specification 4.2 about access_flags.
if(is_interface()) {
// NOTE: Fix for the statement that an interface should have
// abstract flag set.
- // spec/harness/BenchmarkDone has interface flag, but it does not
+ // spec/harness/BenchmarkDone has interface flag, but it does not
// have abstract flag.
m_access_flags |= ACC_ABSTRACT;
}
/*
+ * can't be both final and interface, or both final and abstract
+ * See specification 4.2 about access_flags.
+ */
+ if(is_final() && is_interface())
+ {
+ REPORT_FAILED_CLASS_FORMAT(this, "interface cannot be final");
+ return false;
+ }
+ //not only ACC_FINAL flag is prohibited if is_interface, also ACC_SUPER, ACC_SYNTHETIC, ACC_ENUM.
+ if(is_interface() && (is_super() || is_synthetic() || is_enum()))
+ {
+ REPORT_FAILED_CLASS_FORMAT(this,
+ "if class is interface, no flags except ACC_ABSTRACT or ACC_PUBLIC can be set");
+ return false;
+ }
+ if(is_final() && is_abstract()) {
+ REPORT_FAILED_CLASS_FORMAT(this, "abstract class cannot be final");
+ return false;
+ }
+
+ if(is_annotation() && !is_interface())
+ {
+ REPORT_FAILED_CLASS_FORMAT(this, "annotation type must be interface");
+ return false;
+ }
+
+ if(!is_interface() && is_annotation())
+ {
+ REPORT_FAILED_CLASS_FORMAT(this, "not interface can't be annotation");
+ return false;
+ }
+
+ /*
* parse this_class & super_class & verify their constant pool entries
*/
uint16 this_class;
@@ -2205,6 +2717,7 @@
return false;
}
+ //See specification 4.2 about this_class.
String * class_name = cp_check_class(m_const_pool, this_class);
if (class_name == NULL) {
REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/ClassFormatError",
@@ -2217,7 +2730,7 @@
* When defineClass from byte stream, there are cases that clss->name is null,
* so we should add a check here
*/
- if(m_name != NULL && class_name != m_name) {
+ if(m_name != NULL && class_name != m_name) {
REPORT_FAILED_CLASS_CLASS(m_class_loader, this,
VM_Global_State::loader_env->JavaLangNoClassDefFoundError_String->bytes,
m_name->bytes << ": class name in class data does not match class name passed");
@@ -2246,12 +2759,13 @@
m_super_class.cp_index = super_class;
if (super_class == 0) {
//
- // this class must represent java.lang.Object
+ // This class must represent java.lang.Object
+ // See 4.2 in specification about super_class.
//
if(m_name != env->JavaLangObject_String) {
REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/ClassFormatError",
m_name->bytes << ": class does not contain super class "
- << "but is not java.lang.Object class");
+ << "but is not java.lang.Object class.");
return false;
}
m_super_class.name = NULL;
@@ -2263,6 +2777,12 @@
<< super_class << " is an illegal CONSTANT_Class entry");
return false;
}
+ if(is_interface() && m_super_class.name != env->JavaLangObject_String){
+ REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/ClassFormatError",
+ m_name->bytes << ": the super class of interface is "
+ << m_super_class.name << "; must be java/lang/Object");
+ return false;
+ }
}
/*
@@ -2271,20 +2791,19 @@
if(!parse_interfaces(cfs))
return false;
- /*
+ /*
* allocate and parse class' fields
*/
if(!parse_fields(env, cfs))
return false;
- /*
+ /*
* allocate and parse class' methods
*/
if(!parse_methods(env, cfs))
return false;
-
/*
- * only the FileName attribute is defined for Class
+ * parse attributes
*/
uint16 n_attrs;
if (!cfs.parse_u2_be(&n_attrs)) {
@@ -2292,25 +2811,26 @@
m_name->bytes << ": could not parse number of attributes");
return false;
}
-
- unsigned n_source_file_attr = 0;
+ unsigned numSourceFile = 0;
unsigned numSourceDebugExtensions = 0;
unsigned numEnclosingMethods = 0;
+ unsigned numRuntimeVisibleAnnotations = 0;
+ unsigned numRuntimeInvisibleAnnotations = 0;
uint32 attr_len = 0;
for (unsigned i=0; i 1) {
+ if (++numSourceFile > 1) {
REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/ClassFormatError",
m_name->bytes << ": there is more than one SourceFile attribute");
return false;
}
- // attribute length must be two (vm spec 4.7.2)
+ // attribute length must be two (vm spec 4.8.2)
if (attr_len != 2) {
REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/ClassFormatError",
m_name->bytes << ": SourceFile attribute has incorrect length ("
@@ -2339,6 +2859,7 @@
case ATTR_InnerClasses:
{
+ //See specification 4.8.5 about InnerClasses Attribute
if (m_declaring_class_index || m_innerclasses) {
REPORT_FAILED_CLASS_FORMAT(this, "more than one InnerClasses attribute");
}
@@ -2351,6 +2872,8 @@
isinner = true;
found_myself = 0;
}
+
+ unsigned read_len = 0;
//Only handle inner class
uint16 num_of_classes;
if(!cfs.parse_u2_be(&num_of_classes)) {
@@ -2359,6 +2882,7 @@
<< " while parsing InnerClasses attribute");
return false;
}
+ read_len += 2;
if(isinner)
m_num_innerclasses = (uint16)(num_of_classes - 1); //exclude itself
@@ -2449,8 +2973,13 @@
} else
m_innerclasses[index++].access_flags = inner_clss_access_flag;
} // for num_of_classes
+ read_len += num_of_classes * 8;
+ if(read_len != attr_len){
+ REPORT_FAILED_CLASS_FORMAT(this,
+ "unexpected length of InnerClass attribute: " << read_len << ", expected: " << attr_len);
+ return false;
+ }
}break; //case ATTR_InnerClasses
-
case ATTR_SourceDebugExtension:
{
// attribute length is already recorded in attr_len
@@ -2474,6 +3003,7 @@
case ATTR_EnclosingMethod:
{
+ //See specification 4.8.6
if ( ++numEnclosingMethods > 1 ) {
REPORT_FAILED_CLASS_FORMAT(this, "more than one EnclosingMethod attribute");
return false;
@@ -2485,27 +3015,27 @@
}
uint16 class_idx;
if(!cfs.parse_u2_be(&class_idx)) {
- REPORT_FAILED_CLASS_FORMAT(this,
+ REPORT_FAILED_CLASS_FORMAT(this,
"could not parse class index of EnclosingMethod attribute");
return false;
}
if(!valid_cpi(this, class_idx, CONSTANT_Class))
{
- REPORT_FAILED_CLASS_FORMAT(this,
+ REPORT_FAILED_CLASS_FORMAT(this,
"incorrect class index of EnclosingMethod attribute");
return false;
}
m_enclosing_class_index = class_idx;
-
+ //See specification 4.8.6 about method_index.
uint16 method_idx;
if(!cfs.parse_u2_be(&method_idx)) {
- REPORT_FAILED_CLASS_FORMAT(this,
+ REPORT_FAILED_CLASS_FORMAT(this,
"could not parse method index of EnclosingMethod attribute");
return false;
}
if(method_idx && !valid_cpi(this, method_idx, CONSTANT_NameAndType))
{
- REPORT_FAILED_CLASS_FORMAT(this,
+ REPORT_FAILED_CLASS_FORMAT(this,
"incorrect method index of EnclosingMethod attribute");
return false;
}
@@ -2550,9 +3080,16 @@
case ATTR_RuntimeVisibleAnnotations:
{
+ //ClassFile may contain at most one RuntimeVisibleAnnotations attribute.
+ // See specification 4.8.14.
+ if(++numRuntimeVisibleAnnotations > 1) {
+ REPORT_FAILED_CLASS_FORMAT(this,
+ "more than one RuntimeVisibleAnnotations attribute");
+ return false;
+ }
uint32 read_len = parse_annotation_table(&m_annotations, cfs, this);
if (attr_len != read_len) {
- REPORT_FAILED_CLASS_FORMAT(this,
+ REPORT_FAILED_CLASS_FORMAT(this,
"error parsing Annotations attribute"
<< "; declared length " << attr_len
<< " does not match actual " << read_len);
@@ -2563,6 +3100,12 @@
case ATTR_RuntimeInvisibleAnnotations:
{
+ //ClassFile may contain at most one RuntimeInvisibleAnnotations attribute.
+ if(++numRuntimeInvisibleAnnotations > 1) {
+ REPORT_FAILED_CLASS_FORMAT(this,
+ "more than one RuntimeInvisibleAnnotations attribute");
+ return false;
+ }
if(!cfs.skip(attr_len)) {
REPORT_FAILED_CLASS_FORMAT(this,
"failed to skip RuntimeInvisibleAnnotations attribute");
@@ -2574,11 +3117,14 @@
case ATTR_UNDEF:
// unrecognized attribute; skipped
break;
+ case ATTR_ERROR:
+ return false;
+ break;
default:
// error occured
REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/InternalError",
m_name->bytes << ": unknown error occured"
- " while parsing attributes for class"
+ " while parsing attributes for class"
<< "; unprocessed attribute " << cur_attr);
return false;
} // switch
@@ -2594,33 +3140,7 @@
"InnerClasses presence for class " << m_name->bytes);
}
- /*
- * can't be both final and interface, or both final and abstract
- */
- if(is_final() && is_interface())
- {
- REPORT_FAILED_CLASS_FORMAT(this, "interface cannot be final");
- return false;
- }
-
- if(is_final() && is_abstract()) {
- REPORT_FAILED_CLASS_FORMAT(this, "abstract class cannot be final");
- return false;
- }
- // This requirement seems to be ignored by some compilers
- // if(class_is_interface(clss) && !class_is_abstract(clss))
- //{
- // REPORT_FAILED_CLASS_FORMAT(clss, "interface must have ACC_ABSTRACT flag set");
- // return false;
- //}
-
- if(is_annotation() && !is_interface())
- {
- REPORT_FAILED_CLASS_FORMAT(this, "annotation type must be interface");
- return false;
- }
-
return true;
} // Class::parse
@@ -2789,7 +3309,7 @@
// if no class loader passed, re-route to bootstrap
if(!cl) cl = env->bootstrap_class_loader;
Class* clss = cl->LoadVerifyAndPrepareClass(env, classname);
- return clss;
+ return clss;
}
Index: vm/vmcore/src/util/ia32/base/optimize_ia32.cpp
===================================================================
--- vm/vmcore/src/util/ia32/base/optimize_ia32.cpp (revision 483534)
+++ vm/vmcore/src/util/ia32/base/optimize_ia32.cpp (working copy)
@@ -453,7 +453,7 @@
s = pop(s, ebx_opnd);
s = pop(s, ebp_opnd);
- s = ret(s, Imm_Opnd(method->get_num_arg_bytes()));
+ s = ret(s, Imm_Opnd(method->get_num_arg_slots() * 4));
//Fill Patches
for(; p_c>0 ; p_c--){
Index: vm/vmcore/src/util/ia32/base/compile_IA32.cpp
===================================================================
--- vm/vmcore/src/util/ia32/base/compile_IA32.cpp (revision 483534)
+++ vm/vmcore/src/util/ia32/base/compile_IA32.cpp (working copy)
@@ -85,7 +85,7 @@
assert(!hythread_is_suspend_enabled());
Method_Signature_Handle msh = method_get_signature(method);
unsigned num_args = method_args_get_number(msh);
- unsigned num_arg_words = ((Method*)method)->get_num_arg_bytes()>>2;
+ unsigned num_arg_words = ((Method*)method)->get_num_arg_slots();
unsigned cur_word = 0;
for(unsigned i=0; iget_class()->get_name()->bytes << " "
<< method->get_name()->bytes << " "
<< method->get_descriptor()->bytes);
- int sz = method->get_num_arg_bytes() >> 2;
+ int sz = method->get_num_arg_slots();
void *meth_addr = method->get_code_addr();
uint32 *arg_words = (uint32*) STD_ALLOCA(sz * sizeof(uint32));
Index: vm/interpreter/src/interpreter.cpp
===================================================================
--- vm/interpreter/src/interpreter.cpp (revision 483534)
+++ vm/interpreter/src/interpreter.cpp (working copy)
@@ -3271,7 +3271,7 @@
// Setup locals and stack on C stack.
SETUP_LOCALS_AND_STACK(frame, method);
- int args = method->get_num_arg_bytes() >> 2;
+ int args = method->get_num_arg_slots();
for(int i = args-1; i >= 0; --i) {
frame.locals(i) = prevFrame.stack.pick(args-1 - i);
@@ -3425,7 +3425,7 @@
static void
interpreterInvokeVirtual(StackFrame& prevFrame, Method *method) {
- int args = method->get_num_arg_bytes() >> 2;
+ int args = method->get_num_arg_slots();
CREF cr = prevFrame.stack.pick(args-1).cr;
if (cr == 0) {
@@ -3459,7 +3459,7 @@
static void
interpreterInvokeInterface(StackFrame& prevFrame, Method *method) {
- int args = method->get_num_arg_bytes() >> 2;
+ int args = method->get_num_arg_slots();
CREF cr = prevFrame.stack.pick(args-1).cr;
if (cr == 0) {
@@ -3515,7 +3515,7 @@
static void
interpreterInvokeSpecial(StackFrame& prevFrame, Method *method) {
- int args = method->get_num_arg_bytes() >> 2;
+ int args = method->get_num_arg_slots();
CREF cr = prevFrame.stack.pick(args-1).cr;
if (cr == 0) {
Index: vm/interpreter/src/interp_native_ipf.cpp
===================================================================
--- vm/interpreter/src/interp_native_ipf.cpp (revision 483534)
+++ vm/interpreter/src/interp_native_ipf.cpp (working copy)
@@ -89,7 +89,7 @@
M2N_ALLOC_MACRO;
hythread_suspend_enable();
- int sz = method->get_num_arg_bytes() >> 2;
+ int sz = method->get_num_arg_slots();
uword *arg_words = (uword*) ALLOC_FRAME((sz + 2) * sizeof(uword));
uword fpargs[6 + 1/* for fptypes */];
// types of fpargs[6], 0 - float, 1 - double
@@ -282,7 +282,7 @@
M2N_ALLOC_MACRO;
frame.This = *(method->get_class()->get_class_handle());
- int sz = method->get_num_arg_bytes() >> 2;
+ int sz = method->get_num_arg_slots();
uword *args = (uword*) ALLOC_FRAME((sz + 2) * sizeof(uword));
uword fpargs[6 + 1/* for fptypes */];
// types of fpargs[6], 0 - float, 1 - double
Index: vm/interpreter/src/interp_native_ia32.cpp
===================================================================
--- vm/interpreter/src/interp_native_ia32.cpp (revision 483534)
+++ vm/interpreter/src/interp_native_ia32.cpp (working copy)
@@ -97,7 +97,7 @@
M2N_ALLOC_MACRO;
hythread_suspend_enable();
- int sz = method->get_num_arg_bytes() >> 2;
+ int sz = method->get_num_arg_slots();
uword *arg_words = (uword*) ALLOC_FRAME((sz + 2) * sizeof(uword));
int argId = 0;
@@ -268,7 +268,7 @@
M2N_ALLOC_MACRO;
frame.This = *(method->get_class()->get_class_handle());
- int sz = method->get_num_arg_bytes() >> 2;
+ int sz = method->get_num_arg_slots();
uword *args = (uword*) ALLOC_FRAME((sz + 2) * sizeof(uword));
args[0] = (uword) get_jni_native_intf();
args[1] = (uword) &frame.This;
Index: vm/interpreter/src/interp_native_em64t.cpp
===================================================================
--- vm/interpreter/src/interp_native_em64t.cpp (revision 483534)
+++ vm/interpreter/src/interp_native_em64t.cpp (working copy)
@@ -87,7 +87,7 @@
M2N_ALLOC_MACRO;
hythread_suspend_enable();
- int sz = method->get_num_arg_bytes() >> 2;
+ int sz = method->get_num_arg_slots();
int n_ints = 0;
int n_fps = 0;
@@ -287,7 +287,7 @@
M2N_ALLOC_MACRO;
- word sz = method->get_num_arg_bytes() >> 2;
+ word sz = method->get_num_arg_slots();
int n_ints = 0;
int n_fps = 0;