objArrayKlass.cpp revision 2062:3582bf76420e
1/*
2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25#include "precompiled.hpp"
26#include "classfile/systemDictionary.hpp"
27#include "classfile/vmSymbols.hpp"
28#include "gc_implementation/shared/markSweep.inline.hpp"
29#include "gc_interface/collectedHeap.inline.hpp"
30#include "memory/genOopClosures.inline.hpp"
31#include "memory/resourceArea.hpp"
32#include "memory/universe.inline.hpp"
33#include "oops/instanceKlass.hpp"
34#include "oops/objArrayKlass.hpp"
35#include "oops/objArrayKlass.inline.hpp"
36#include "oops/objArrayKlassKlass.hpp"
37#include "oops/objArrayOop.hpp"
38#include "oops/oop.inline.hpp"
39#include "oops/oop.inline2.hpp"
40#include "oops/symbol.hpp"
41#include "runtime/handles.inline.hpp"
42#include "runtime/mutexLocker.hpp"
43#include "utilities/copy.hpp"
44#ifndef SERIALGC
45#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
46#include "gc_implementation/g1/g1OopClosures.inline.hpp"
47#include "gc_implementation/g1/g1RemSet.inline.hpp"
48#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
49#include "gc_implementation/parNew/parOopClosures.inline.hpp"
50#include "gc_implementation/parallelScavenge/psCompactionManager.hpp"
51#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp"
52#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp"
53#include "oops/oop.pcgc.inline.hpp"
54#endif
55
56int objArrayKlass::oop_size(oop obj) const {
57  assert(obj->is_objArray(), "must be object array");
58  return objArrayOop(obj)->object_size();
59}
60
61objArrayOop objArrayKlass::allocate(int length, TRAPS) {
62  if (length >= 0) {
63    if (length <= arrayOopDesc::max_array_length(T_OBJECT)) {
64      int size = objArrayOopDesc::object_size(length);
65      KlassHandle h_k(THREAD, as_klassOop());
66      objArrayOop a = (objArrayOop)CollectedHeap::array_allocate(h_k, size, length, CHECK_NULL);
67      assert(a->is_parsable(), "Can't publish unless parsable");
68      return a;
69    } else {
70      report_java_out_of_memory("Requested array size exceeds VM limit");
71      THROW_OOP_0(Universe::out_of_memory_error_array_size());
72    }
73  } else {
74    THROW_0(vmSymbols::java_lang_NegativeArraySizeException());
75  }
76}
77
78static int multi_alloc_counter = 0;
79
80oop objArrayKlass::multi_allocate(int rank, jint* sizes, TRAPS) {
81  int length = *sizes;
82  // Call to lower_dimension uses this pointer, so most be called before a
83  // possible GC
84  KlassHandle h_lower_dimension(THREAD, lower_dimension());
85  // If length < 0 allocate will throw an exception.
86  objArrayOop array = allocate(length, CHECK_NULL);
87  assert(array->is_parsable(), "Don't handlize unless parsable");
88  objArrayHandle h_array (THREAD, array);
89  if (rank > 1) {
90    if (length != 0) {
91      for (int index = 0; index < length; index++) {
92        arrayKlass* ak = arrayKlass::cast(h_lower_dimension());
93        oop sub_array = ak->multi_allocate(rank-1, &sizes[1], CHECK_NULL);
94        assert(sub_array->is_parsable(), "Don't publish until parsable");
95        h_array->obj_at_put(index, sub_array);
96      }
97    } else {
98      // Since this array dimension has zero length, nothing will be
99      // allocated, however the lower dimension values must be checked
100      // for illegal values.
101      for (int i = 0; i < rank - 1; ++i) {
102        sizes += 1;
103        if (*sizes < 0) {
104          THROW_0(vmSymbols::java_lang_NegativeArraySizeException());
105        }
106      }
107    }
108  }
109  return h_array();
110}
111
112// Either oop or narrowOop depending on UseCompressedOops.
113template <class T> void objArrayKlass::do_copy(arrayOop s, T* src,
114                               arrayOop d, T* dst, int length, TRAPS) {
115
116  BarrierSet* bs = Universe::heap()->barrier_set();
117  // For performance reasons, we assume we are that the write barrier we
118  // are using has optimized modes for arrays of references.  At least one
119  // of the asserts below will fail if this is not the case.
120  assert(bs->has_write_ref_array_opt(), "Barrier set must have ref array opt");
121  assert(bs->has_write_ref_array_pre_opt(), "For pre-barrier as well.");
122
123  if (s == d) {
124    // since source and destination are equal we do not need conversion checks.
125    assert(length > 0, "sanity check");
126    bs->write_ref_array_pre(dst, length);
127    Copy::conjoint_oops_atomic(src, dst, length);
128  } else {
129    // We have to make sure all elements conform to the destination array
130    klassOop bound = objArrayKlass::cast(d->klass())->element_klass();
131    klassOop stype = objArrayKlass::cast(s->klass())->element_klass();
132    if (stype == bound || Klass::cast(stype)->is_subtype_of(bound)) {
133      // elements are guaranteed to be subtypes, so no check necessary
134      bs->write_ref_array_pre(dst, length);
135      Copy::conjoint_oops_atomic(src, dst, length);
136    } else {
137      // slow case: need individual subtype checks
138      // note: don't use obj_at_put below because it includes a redundant store check
139      T* from = src;
140      T* end = from + length;
141      for (T* p = dst; from < end; from++, p++) {
142        // XXX this is going to be slow.
143        T element = *from;
144        // even slower now
145        bool element_is_null = oopDesc::is_null(element);
146        oop new_val = element_is_null ? oop(NULL)
147                                      : oopDesc::decode_heap_oop_not_null(element);
148        if (element_is_null ||
149            Klass::cast((new_val->klass()))->is_subtype_of(bound)) {
150          bs->write_ref_field_pre(p, new_val);
151          *p = *from;
152        } else {
153          // We must do a barrier to cover the partial copy.
154          const size_t pd = pointer_delta(p, dst, (size_t)heapOopSize);
155          // pointer delta is scaled to number of elements (length field in
156          // objArrayOop) which we assume is 32 bit.
157          assert(pd == (size_t)(int)pd, "length field overflow");
158          bs->write_ref_array((HeapWord*)dst, pd);
159          THROW(vmSymbols::java_lang_ArrayStoreException());
160          return;
161        }
162      }
163    }
164  }
165  bs->write_ref_array((HeapWord*)dst, length);
166}
167
168void objArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d,
169                               int dst_pos, int length, TRAPS) {
170  assert(s->is_objArray(), "must be obj array");
171
172  if (!d->is_objArray()) {
173    THROW(vmSymbols::java_lang_ArrayStoreException());
174  }
175
176  // Check is all offsets and lengths are non negative
177  if (src_pos < 0 || dst_pos < 0 || length < 0) {
178    THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException());
179  }
180  // Check if the ranges are valid
181  if  ( (((unsigned int) length + (unsigned int) src_pos) > (unsigned int) s->length())
182     || (((unsigned int) length + (unsigned int) dst_pos) > (unsigned int) d->length()) ) {
183    THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException());
184  }
185
186  // Special case. Boundary cases must be checked first
187  // This allows the following call: copy_array(s, s.length(), d.length(), 0).
188  // This is correct, since the position is supposed to be an 'in between point', i.e., s.length(),
189  // points to the right of the last element.
190  if (length==0) {
191    return;
192  }
193  if (UseCompressedOops) {
194    narrowOop* const src = objArrayOop(s)->obj_at_addr<narrowOop>(src_pos);
195    narrowOop* const dst = objArrayOop(d)->obj_at_addr<narrowOop>(dst_pos);
196    do_copy<narrowOop>(s, src, d, dst, length, CHECK);
197  } else {
198    oop* const src = objArrayOop(s)->obj_at_addr<oop>(src_pos);
199    oop* const dst = objArrayOop(d)->obj_at_addr<oop>(dst_pos);
200    do_copy<oop> (s, src, d, dst, length, CHECK);
201  }
202}
203
204
205klassOop objArrayKlass::array_klass_impl(bool or_null, int n, TRAPS) {
206  objArrayKlassHandle h_this(THREAD, as_klassOop());
207  return array_klass_impl(h_this, or_null, n, CHECK_NULL);
208}
209
210
211klassOop objArrayKlass::array_klass_impl(objArrayKlassHandle this_oop, bool or_null, int n, TRAPS) {
212
213  assert(this_oop->dimension() <= n, "check order of chain");
214  int dimension = this_oop->dimension();
215  if (dimension == n)
216    return this_oop();
217
218  objArrayKlassHandle ak (THREAD, this_oop->higher_dimension());
219  if (ak.is_null()) {
220    if (or_null)  return NULL;
221
222    ResourceMark rm;
223    JavaThread *jt = (JavaThread *)THREAD;
224    {
225      MutexLocker mc(Compile_lock, THREAD);   // for vtables
226      // Ensure atomic creation of higher dimensions
227      MutexLocker mu(MultiArray_lock, THREAD);
228
229      // Check if another thread beat us
230      ak = objArrayKlassHandle(THREAD, this_oop->higher_dimension());
231      if( ak.is_null() ) {
232
233        // Create multi-dim klass object and link them together
234        klassOop new_klass =
235          objArrayKlassKlass::cast(Universe::objArrayKlassKlassObj())->
236          allocate_objArray_klass(dimension + 1, this_oop, CHECK_NULL);
237        ak = objArrayKlassHandle(THREAD, new_klass);
238        ak->set_lower_dimension(this_oop());
239        OrderAccess::storestore();
240        this_oop->set_higher_dimension(ak());
241        assert(ak->oop_is_objArray(), "incorrect initialization of objArrayKlass");
242      }
243    }
244  } else {
245    CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
246  }
247
248  if (or_null) {
249    return ak->array_klass_or_null(n);
250  }
251  return ak->array_klass(n, CHECK_NULL);
252}
253
254klassOop objArrayKlass::array_klass_impl(bool or_null, TRAPS) {
255  return array_klass_impl(or_null, dimension() +  1, CHECK_NULL);
256}
257
258bool objArrayKlass::can_be_primary_super_slow() const {
259  if (!bottom_klass()->klass_part()->can_be_primary_super())
260    // array of interfaces
261    return false;
262  else
263    return Klass::can_be_primary_super_slow();
264}
265
266objArrayOop objArrayKlass::compute_secondary_supers(int num_extra_slots, TRAPS) {
267  // interfaces = { cloneable_klass, serializable_klass, elemSuper[], ... };
268  objArrayOop es = Klass::cast(element_klass())->secondary_supers();
269  objArrayHandle elem_supers (THREAD, es);
270  int num_elem_supers = elem_supers.is_null() ? 0 : elem_supers->length();
271  int num_secondaries = num_extra_slots + 2 + num_elem_supers;
272  if (num_secondaries == 2) {
273    // Must share this for correct bootstrapping!
274    return Universe::the_array_interfaces_array();
275  } else {
276    objArrayOop sec_oop = oopFactory::new_system_objArray(num_secondaries, CHECK_NULL);
277    objArrayHandle secondaries(THREAD, sec_oop);
278    secondaries->obj_at_put(num_extra_slots+0, SystemDictionary::Cloneable_klass());
279    secondaries->obj_at_put(num_extra_slots+1, SystemDictionary::Serializable_klass());
280    for (int i = 0; i < num_elem_supers; i++) {
281      klassOop elem_super = (klassOop) elem_supers->obj_at(i);
282      klassOop array_super = elem_super->klass_part()->array_klass_or_null();
283      assert(array_super != NULL, "must already have been created");
284      secondaries->obj_at_put(num_extra_slots+2+i, array_super);
285    }
286    return secondaries();
287  }
288}
289
290bool objArrayKlass::compute_is_subtype_of(klassOop k) {
291  if (!k->klass_part()->oop_is_objArray())
292    return arrayKlass::compute_is_subtype_of(k);
293
294  objArrayKlass* oak = objArrayKlass::cast(k);
295  return element_klass()->klass_part()->is_subtype_of(oak->element_klass());
296}
297
298void objArrayKlass::initialize(TRAPS) {
299  Klass::cast(bottom_klass())->initialize(THREAD);  // dispatches to either instanceKlass or typeArrayKlass
300}
301
302#define ObjArrayKlass_SPECIALIZED_OOP_ITERATE(T, a, p, do_oop) \
303{                                   \
304  T* p         = (T*)(a)->base();   \
305  T* const end = p + (a)->length(); \
306  while (p < end) {                 \
307    do_oop;                         \
308    p++;                            \
309  }                                 \
310}
311
312#define ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(T, a, p, low, high, do_oop) \
313{                                   \
314  T* const l = (T*)(low);           \
315  T* const h = (T*)(high);          \
316  T* p       = (T*)(a)->base();     \
317  T* end     = p + (a)->length();   \
318  if (p < l) p = l;                 \
319  if (end > h) end = h;             \
320  while (p < end) {                 \
321    do_oop;                         \
322    ++p;                            \
323  }                                 \
324}
325
326#define ObjArrayKlass_OOP_ITERATE(a, p, do_oop)      \
327  if (UseCompressedOops) {                           \
328    ObjArrayKlass_SPECIALIZED_OOP_ITERATE(narrowOop, \
329      a, p, do_oop)                                  \
330  } else {                                           \
331    ObjArrayKlass_SPECIALIZED_OOP_ITERATE(oop,       \
332      a, p, do_oop)                                  \
333  }
334
335#define ObjArrayKlass_BOUNDED_OOP_ITERATE(a, p, low, high, do_oop) \
336  if (UseCompressedOops) {                                   \
337    ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(narrowOop, \
338      a, p, low, high, do_oop)                               \
339  } else {                                                   \
340    ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(oop,       \
341      a, p, low, high, do_oop)                               \
342  }
343
344void objArrayKlass::oop_follow_contents(oop obj) {
345  assert (obj->is_array(), "obj must be array");
346  objArrayOop(obj)->follow_header();
347  if (UseCompressedOops) {
348    objarray_follow_contents<narrowOop>(obj, 0);
349  } else {
350    objarray_follow_contents<oop>(obj, 0);
351  }
352}
353
354#ifndef SERIALGC
355void objArrayKlass::oop_follow_contents(ParCompactionManager* cm,
356                                        oop obj) {
357  assert(obj->is_array(), "obj must be array");
358  objArrayOop(obj)->follow_header(cm);
359  if (UseCompressedOops) {
360    objarray_follow_contents<narrowOop>(cm, obj, 0);
361  } else {
362    objarray_follow_contents<oop>(cm, obj, 0);
363  }
364}
365#endif // SERIALGC
366
367#define ObjArrayKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)           \
368                                                                                \
369int objArrayKlass::oop_oop_iterate##nv_suffix(oop obj,                          \
370                                              OopClosureType* closure) {        \
371  SpecializationStats::record_iterate_call##nv_suffix(SpecializationStats::oa); \
372  assert (obj->is_array(), "obj must be array");                                \
373  objArrayOop a = objArrayOop(obj);                                             \
374  /* Get size before changing pointers. */                                      \
375  /* Don't call size() or oop_size() since that is a virtual call. */           \
376  int size = a->object_size();                                                  \
377  if (closure->do_header()) {                                                   \
378    a->oop_iterate_header(closure);                                             \
379  }                                                                             \
380  ObjArrayKlass_OOP_ITERATE(a, p, (closure)->do_oop##nv_suffix(p))              \
381  return size;                                                                  \
382}
383
384#define ObjArrayKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix)         \
385                                                                                \
386int objArrayKlass::oop_oop_iterate##nv_suffix##_m(oop obj,                      \
387                                                  OopClosureType* closure,      \
388                                                  MemRegion mr) {               \
389  SpecializationStats::record_iterate_call##nv_suffix(SpecializationStats::oa); \
390  assert(obj->is_array(), "obj must be array");                                 \
391  objArrayOop a  = objArrayOop(obj);                                            \
392  /* Get size before changing pointers. */                                      \
393  /* Don't call size() or oop_size() since that is a virtual call */            \
394  int size = a->object_size();                                                  \
395  if (closure->do_header()) {                                                   \
396    a->oop_iterate_header(closure, mr);                                         \
397  }                                                                             \
398  ObjArrayKlass_BOUNDED_OOP_ITERATE(                                            \
399    a, p, mr.start(), mr.end(), (closure)->do_oop##nv_suffix(p))                \
400  return size;                                                                  \
401}
402
403// Like oop_oop_iterate but only iterates over a specified range and only used
404// for objArrayOops.
405#define ObjArrayKlass_OOP_OOP_ITERATE_DEFN_r(OopClosureType, nv_suffix)         \
406                                                                                \
407int objArrayKlass::oop_oop_iterate_range##nv_suffix(oop obj,                    \
408                                                  OopClosureType* closure,      \
409                                                  int start, int end) {         \
410  SpecializationStats::record_iterate_call##nv_suffix(SpecializationStats::oa); \
411  assert(obj->is_array(), "obj must be array");                                 \
412  objArrayOop a  = objArrayOop(obj);                                            \
413  /* Get size before changing pointers. */                                      \
414  /* Don't call size() or oop_size() since that is a virtual call */            \
415  int size = a->object_size();                                                  \
416  if (UseCompressedOops) {                                                      \
417    HeapWord* low = start == 0 ? (HeapWord*)a : (HeapWord*)a->obj_at_addr<narrowOop>(start);\
418    /* this might be wierd if end needs to be aligned on HeapWord boundary */   \
419    HeapWord* high = (HeapWord*)((narrowOop*)a->base() + end);                  \
420    MemRegion mr(low, high);                                                    \
421    if (closure->do_header()) {                                                 \
422      a->oop_iterate_header(closure, mr);                                       \
423    }                                                                           \
424    ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(narrowOop,                    \
425      a, p, low, high, (closure)->do_oop##nv_suffix(p))                         \
426  } else {                                                                      \
427    HeapWord* low = start == 0 ? (HeapWord*)a : (HeapWord*)a->obj_at_addr<oop>(start);  \
428    HeapWord* high = (HeapWord*)((oop*)a->base() + end);                        \
429    MemRegion mr(low, high);                                                    \
430    if (closure->do_header()) {                                                 \
431      a->oop_iterate_header(closure, mr);                                       \
432    }                                                                           \
433    ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(oop,                          \
434      a, p, low, high, (closure)->do_oop##nv_suffix(p))                         \
435  }                                                                             \
436  return size;                                                                  \
437}
438
439ALL_OOP_OOP_ITERATE_CLOSURES_1(ObjArrayKlass_OOP_OOP_ITERATE_DEFN)
440ALL_OOP_OOP_ITERATE_CLOSURES_2(ObjArrayKlass_OOP_OOP_ITERATE_DEFN)
441ALL_OOP_OOP_ITERATE_CLOSURES_1(ObjArrayKlass_OOP_OOP_ITERATE_DEFN_m)
442ALL_OOP_OOP_ITERATE_CLOSURES_2(ObjArrayKlass_OOP_OOP_ITERATE_DEFN_m)
443ALL_OOP_OOP_ITERATE_CLOSURES_1(ObjArrayKlass_OOP_OOP_ITERATE_DEFN_r)
444ALL_OOP_OOP_ITERATE_CLOSURES_2(ObjArrayKlass_OOP_OOP_ITERATE_DEFN_r)
445
446int objArrayKlass::oop_adjust_pointers(oop obj) {
447  assert(obj->is_objArray(), "obj must be obj array");
448  objArrayOop a = objArrayOop(obj);
449  // Get size before changing pointers.
450  // Don't call size() or oop_size() since that is a virtual call.
451  int size = a->object_size();
452  a->adjust_header();
453  ObjArrayKlass_OOP_ITERATE(a, p, MarkSweep::adjust_pointer(p))
454  return size;
455}
456
457#ifndef SERIALGC
458void objArrayKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
459  assert(obj->is_objArray(), "obj must be obj array");
460  ObjArrayKlass_OOP_ITERATE( \
461    objArrayOop(obj), p, \
462    if (PSScavenge::should_scavenge(p)) { \
463      pm->claim_or_forward_depth(p); \
464    })
465}
466
467int objArrayKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) {
468  assert (obj->is_objArray(), "obj must be obj array");
469  objArrayOop a = objArrayOop(obj);
470  ObjArrayKlass_OOP_ITERATE(a, p, PSParallelCompact::adjust_pointer(p))
471  return a->object_size();
472}
473
474int objArrayKlass::oop_update_pointers(ParCompactionManager* cm, oop obj,
475                                       HeapWord* beg_addr, HeapWord* end_addr) {
476  assert (obj->is_objArray(), "obj must be obj array");
477  objArrayOop a = objArrayOop(obj);
478  ObjArrayKlass_BOUNDED_OOP_ITERATE( \
479     a, p, beg_addr, end_addr, \
480     PSParallelCompact::adjust_pointer(p))
481  return a->object_size();
482}
483#endif // SERIALGC
484
485// JVM support
486
487jint objArrayKlass::compute_modifier_flags(TRAPS) const {
488  // The modifier for an objectArray is the same as its element
489  if (element_klass() == NULL) {
490    assert(Universe::is_bootstrapping(), "partial objArray only at startup");
491    return JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC;
492  }
493  // Return the flags of the bottom element type.
494  jint element_flags = Klass::cast(bottom_klass())->compute_modifier_flags(CHECK_0);
495
496  return (element_flags & (JVM_ACC_PUBLIC | JVM_ACC_PRIVATE | JVM_ACC_PROTECTED))
497                        | (JVM_ACC_ABSTRACT | JVM_ACC_FINAL);
498}
499
500
501#ifndef PRODUCT
502// Printing
503
504void objArrayKlass::oop_print_on(oop obj, outputStream* st) {
505  arrayKlass::oop_print_on(obj, st);
506  assert(obj->is_objArray(), "must be objArray");
507  objArrayOop oa = objArrayOop(obj);
508  int print_len = MIN2((intx) oa->length(), MaxElementPrintSize);
509  for(int index = 0; index < print_len; index++) {
510    st->print(" - %3d : ", index);
511    oa->obj_at(index)->print_value_on(st);
512    st->cr();
513  }
514  int remaining = oa->length() - print_len;
515  if (remaining > 0) {
516    tty->print_cr(" - <%d more elements, increase MaxElementPrintSize to print>", remaining);
517  }
518}
519
520#endif //PRODUCT
521
522static int max_objArray_print_length = 4;
523
524void objArrayKlass::oop_print_value_on(oop obj, outputStream* st) {
525  assert(obj->is_objArray(), "must be objArray");
526  st->print("a ");
527  element_klass()->print_value_on(st);
528  int len = objArrayOop(obj)->length();
529  st->print("[%d] ", len);
530  obj->print_address_on(st);
531  if (NOT_PRODUCT(PrintOopAddress ||) PrintMiscellaneous && (WizardMode || Verbose)) {
532    st->print("{");
533    for (int i = 0; i < len; i++) {
534      if (i > max_objArray_print_length) {
535        st->print("..."); break;
536      }
537      st->print(" "INTPTR_FORMAT, (intptr_t)(void*)objArrayOop(obj)->obj_at(i));
538    }
539    st->print(" }");
540  }
541}
542
543const char* objArrayKlass::internal_name() const {
544  return external_name();
545}
546
547// Verification
548
549void objArrayKlass::oop_verify_on(oop obj, outputStream* st) {
550  arrayKlass::oop_verify_on(obj, st);
551  guarantee(obj->is_objArray(), "must be objArray");
552  objArrayOop oa = objArrayOop(obj);
553  for(int index = 0; index < oa->length(); index++) {
554    guarantee(oa->obj_at(index)->is_oop_or_null(), "should be oop");
555  }
556}
557
558void objArrayKlass::oop_verify_old_oop(oop obj, oop* p, bool allow_dirty) {
559  /* $$$ move into remembered set verification?
560  RememberedSet::verify_old_oop(obj, p, allow_dirty, true);
561  */
562}
563void objArrayKlass::oop_verify_old_oop(oop obj, narrowOop* p, bool allow_dirty) {}
564