+ uninitialized_reference_type
+ };
+
+ // This represents a merged class type. Some verifiers (including
+ // earlier versions of this one) will compute the intersection of
+ // two class types when merging states. However, this loses
+ // critical information about interfaces implemented by the various
+ // classes. So instead we keep track of all the actual classes that
+ // have been merged.
+ struct ref_intersection
+ {
+ // Whether or not this type has been resolved.
+ bool is_resolved;
+
+ // Actual type data.
+ union
+ {
+ // For a resolved reference type, this is a pointer to the class.
+ jclass klass;
+ // For other reference types, this it the name of the class.
+ _Jv_Utf8Const *name;
+ } data;
+
+ // Link to the next reference in the intersection.
+ ref_intersection *ref_next;
+
+ // This is used to keep track of all the allocated
+ // ref_intersection objects, so we can free them.
+ // FIXME: we should allocate these in chunks.
+ ref_intersection *alloc_next;
+
+ ref_intersection (jclass klass, _Jv_BytecodeVerifier *verifier)
+ : ref_next (NULL)
+ {
+ is_resolved = true;
+ data.klass = klass;
+ alloc_next = verifier->isect_list;
+ verifier->isect_list = this;
+ }
+
+ ref_intersection (_Jv_Utf8Const *name, _Jv_BytecodeVerifier *verifier)
+ : ref_next (NULL)
+ {
+ is_resolved = false;
+ data.name = name;
+ alloc_next = verifier->isect_list;
+ verifier->isect_list = this;
+ }
+
+ ref_intersection (ref_intersection *dup, ref_intersection *tail,
+ _Jv_BytecodeVerifier *verifier)
+ : ref_next (tail)
+ {
+ is_resolved = dup->is_resolved;
+ data = dup->data;
+ alloc_next = verifier->isect_list;
+ verifier->isect_list = this;
+ }
+
+ bool equals (ref_intersection *other, _Jv_BytecodeVerifier *verifier)
+ {
+ if (! is_resolved && ! other->is_resolved
+ && _Jv_equalUtf8Classnames (data.name, other->data.name))
+ return true;
+ if (! is_resolved)
+ resolve (verifier);
+ if (! other->is_resolved)
+ other->resolve (verifier);
+ return data.klass == other->data.klass;
+ }
+
+ // Merge THIS type into OTHER, returning the result. This will
+ // return OTHER if all the classes in THIS already appear in
+ // OTHER.
+ ref_intersection *merge (ref_intersection *other,
+ _Jv_BytecodeVerifier *verifier)
+ {
+ ref_intersection *tail = other;
+ for (ref_intersection *self = this; self != NULL; self = self->ref_next)
+ {
+ bool add = true;
+ for (ref_intersection *iter = other; iter != NULL;
+ iter = iter->ref_next)
+ {
+ if (iter->equals (self, verifier))
+ {
+ add = false;
+ break;
+ }
+ }
+
+ if (add)
+ tail = new ref_intersection (self, tail, verifier);
+ }
+ return tail;
+ }
+
+ void resolve (_Jv_BytecodeVerifier *verifier)
+ {
+ if (is_resolved)
+ return;
+
+ // This is useful if you want to see which classes have to be resolved
+ // while doing the class verification.
+ debug_print("resolving class: %s\n", data.name->chars());
+
+ using namespace java::lang;
+ java::lang::ClassLoader *loader
+ = verifier->current_class->getClassLoaderInternal();
+
+ // Due to special handling in to_array() array classes will always
+ // be of the "L ... ;" kind. The separator char ('.' or '/' may vary
+ // however.
+ if (data.name->limit()[-1] == ';')
+ {
+ data.klass = _Jv_FindClassFromSignature (data.name->chars(), loader);
+ if (data.klass == NULL)
+ throw new java::lang::NoClassDefFoundError(data.name->toString());
+ }
+ else
+ data.klass = Class::forName (_Jv_NewStringUtf8Const (data.name),
+ false, loader);
+ is_resolved = true;
+ }
+
+ // See if an object of type OTHER can be assigned to an object of
+ // type *THIS. This might resolve classes in one chain or the
+ // other.
+ bool compatible (ref_intersection *other,
+ _Jv_BytecodeVerifier *verifier)
+ {
+ ref_intersection *self = this;
+
+ for (; self != NULL; self = self->ref_next)
+ {
+ ref_intersection *other_iter = other;
+
+ for (; other_iter != NULL; other_iter = other_iter->ref_next)
+ {
+ // Avoid resolving if possible.
+ if (! self->is_resolved
+ && ! other_iter->is_resolved
+ && _Jv_equalUtf8Classnames (self->data.name,
+ other_iter->data.name))
+ continue;
+
+ if (! self->is_resolved)
+ self->resolve(verifier);
+
+ // If the LHS of the expression is of type
+ // java.lang.Object, assignment will succeed, no matter
+ // what the type of the RHS is. Using this short-cut we
+ // don't need to resolve the class of the RHS at
+ // verification time.
+ if (self->data.klass == &java::lang::Object::class$)
+ continue;
+
+ if (! other_iter->is_resolved)
+ other_iter->resolve(verifier);
+
+ if (! is_assignable_from_slow (self->data.klass,
+ other_iter->data.klass))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool isarray ()
+ {
+ // assert (ref_next == NULL);
+ if (is_resolved)
+ return data.klass->isArray ();
+ else
+ return data.name->first() == '[';
+ }
+
+ bool isinterface (_Jv_BytecodeVerifier *verifier)
+ {
+ // assert (ref_next == NULL);
+ if (! is_resolved)
+ resolve (verifier);
+ return data.klass->isInterface ();
+ }
+
+ bool isabstract (_Jv_BytecodeVerifier *verifier)
+ {
+ // assert (ref_next == NULL);
+ if (! is_resolved)
+ resolve (verifier);
+ using namespace java::lang::reflect;
+ return Modifier::isAbstract (data.klass->getModifiers ());
+ }
+
+ jclass getclass (_Jv_BytecodeVerifier *verifier)
+ {
+ if (! is_resolved)
+ resolve (verifier);
+ return data.klass;
+ }
+
+ int count_dimensions ()
+ {
+ int ndims = 0;
+ if (is_resolved)
+ {
+ jclass k = data.klass;
+ while (k->isArray ())
+ {
+ k = k->getComponentType ();
+ ++ndims;
+ }
+ }
+ else
+ {
+ char *p = data.name->chars();
+ while (*p++ == '[')
+ ++ndims;
+ }
+ return ndims;
+ }
+
+ void *operator new (size_t bytes)
+ {
+ return _Jv_Malloc (bytes);
+ }
+
+ void operator delete (void *mem)
+ {
+ _Jv_Free (mem);
+ }