| 1 | /* | 
|---|
| 2 | * Copyright (c) 1997, 2019, 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/moduleEntry.hpp" | 
|---|
| 27 | #include "classfile/packageEntry.hpp" | 
|---|
| 28 | #include "classfile/symbolTable.hpp" | 
|---|
| 29 | #include "classfile/systemDictionary.hpp" | 
|---|
| 30 | #include "classfile/vmSymbols.hpp" | 
|---|
| 31 | #include "gc/shared/collectedHeap.hpp" | 
|---|
| 32 | #include "gc/shared/collectedHeap.inline.hpp" | 
|---|
| 33 | #include "memory/metadataFactory.hpp" | 
|---|
| 34 | #include "memory/resourceArea.hpp" | 
|---|
| 35 | #include "memory/universe.hpp" | 
|---|
| 36 | #include "oops/arrayKlass.inline.hpp" | 
|---|
| 37 | #include "oops/instanceKlass.hpp" | 
|---|
| 38 | #include "oops/klass.inline.hpp" | 
|---|
| 39 | #include "oops/objArrayKlass.hpp" | 
|---|
| 40 | #include "oops/oop.inline.hpp" | 
|---|
| 41 | #include "oops/typeArrayKlass.inline.hpp" | 
|---|
| 42 | #include "oops/typeArrayOop.inline.hpp" | 
|---|
| 43 | #include "runtime/handles.inline.hpp" | 
|---|
| 44 | #include "utilities/macros.hpp" | 
|---|
| 45 |  | 
|---|
| 46 | TypeArrayKlass* TypeArrayKlass::create_klass(BasicType type, | 
|---|
| 47 | const char* name_str, TRAPS) { | 
|---|
| 48 | Symbol* sym = NULL; | 
|---|
| 49 | if (name_str != NULL) { | 
|---|
| 50 | sym = SymbolTable::new_permanent_symbol(name_str); | 
|---|
| 51 | } | 
|---|
| 52 |  | 
|---|
| 53 | ClassLoaderData* null_loader_data = ClassLoaderData::the_null_class_loader_data(); | 
|---|
| 54 |  | 
|---|
| 55 | TypeArrayKlass* ak = TypeArrayKlass::allocate(null_loader_data, type, sym, CHECK_NULL); | 
|---|
| 56 |  | 
|---|
| 57 | // Call complete_create_array_klass after all instance variables have been initialized. | 
|---|
| 58 | complete_create_array_klass(ak, ak->super(), ModuleEntryTable::javabase_moduleEntry(), CHECK_NULL); | 
|---|
| 59 |  | 
|---|
| 60 | // Add all classes to our internal class loader list here, | 
|---|
| 61 | // including classes in the bootstrap (NULL) class loader. | 
|---|
| 62 | // Do this step after creating the mirror so that if the | 
|---|
| 63 | // mirror creation fails, loaded_classes_do() doesn't find | 
|---|
| 64 | // an array class without a mirror. | 
|---|
| 65 | null_loader_data->add_class(ak); | 
|---|
| 66 |  | 
|---|
| 67 | return ak; | 
|---|
| 68 | } | 
|---|
| 69 |  | 
|---|
| 70 | TypeArrayKlass* TypeArrayKlass::allocate(ClassLoaderData* loader_data, BasicType type, Symbol* name, TRAPS) { | 
|---|
| 71 | assert(TypeArrayKlass::header_size() <= InstanceKlass::header_size(), | 
|---|
| 72 | "array klasses must be same size as InstanceKlass"); | 
|---|
| 73 |  | 
|---|
| 74 | int size = ArrayKlass::static_size(TypeArrayKlass::header_size()); | 
|---|
| 75 |  | 
|---|
| 76 | return new (loader_data, size, THREAD) TypeArrayKlass(type, name); | 
|---|
| 77 | } | 
|---|
| 78 |  | 
|---|
| 79 | TypeArrayKlass::TypeArrayKlass(BasicType type, Symbol* name) : ArrayKlass(name, ID) { | 
|---|
| 80 | set_layout_helper(array_layout_helper(type)); | 
|---|
| 81 | assert(is_array_klass(), "sanity"); | 
|---|
| 82 | assert(is_typeArray_klass(), "sanity"); | 
|---|
| 83 |  | 
|---|
| 84 | set_max_length(arrayOopDesc::max_array_length(type)); | 
|---|
| 85 | assert(size() >= TypeArrayKlass::header_size(), "bad size"); | 
|---|
| 86 |  | 
|---|
| 87 | set_class_loader_data(ClassLoaderData::the_null_class_loader_data()); | 
|---|
| 88 | } | 
|---|
| 89 |  | 
|---|
| 90 | typeArrayOop TypeArrayKlass::allocate_common(int length, bool do_zero, TRAPS) { | 
|---|
| 91 | assert(log2_element_size() >= 0, "bad scale"); | 
|---|
| 92 | check_array_allocation_length(length, max_length(), CHECK_NULL); | 
|---|
| 93 | size_t size = typeArrayOopDesc::object_size(layout_helper(), length); | 
|---|
| 94 | return (typeArrayOop)Universe::heap()->array_allocate(this, (int)size, length, | 
|---|
| 95 | do_zero, CHECK_NULL); | 
|---|
| 96 | } | 
|---|
| 97 |  | 
|---|
| 98 | oop TypeArrayKlass::multi_allocate(int rank, jint* last_size, TRAPS) { | 
|---|
| 99 | // For typeArrays this is only called for the last dimension | 
|---|
| 100 | assert(rank == 1, "just checking"); | 
|---|
| 101 | int length = *last_size; | 
|---|
| 102 | return allocate(length, THREAD); | 
|---|
| 103 | } | 
|---|
| 104 |  | 
|---|
| 105 |  | 
|---|
| 106 | void TypeArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d, int dst_pos, int length, TRAPS) { | 
|---|
| 107 | assert(s->is_typeArray(), "must be type array"); | 
|---|
| 108 |  | 
|---|
| 109 | // Check destination type. | 
|---|
| 110 | if (!d->is_typeArray()) { | 
|---|
| 111 | ResourceMark rm(THREAD); | 
|---|
| 112 | stringStream ss; | 
|---|
| 113 | if (d->is_objArray()) { | 
|---|
| 114 | ss.print( "arraycopy: type mismatch: can not copy %s[] into object array[]", | 
|---|
| 115 | type2name_tab[ArrayKlass::cast(s->klass())->element_type()]); | 
|---|
| 116 | } else { | 
|---|
| 117 | ss.print( "arraycopy: destination type %s is not an array", d->klass()->external_name()); | 
|---|
| 118 | } | 
|---|
| 119 | THROW_MSG(vmSymbols::java_lang_ArrayStoreException(), ss.as_string()); | 
|---|
| 120 | } | 
|---|
| 121 | if (element_type() != TypeArrayKlass::cast(d->klass())->element_type()) { | 
|---|
| 122 | ResourceMark rm(THREAD); | 
|---|
| 123 | stringStream ss; | 
|---|
| 124 | ss.print( "arraycopy: type mismatch: can not copy %s[] into %s[]", | 
|---|
| 125 | type2name_tab[ArrayKlass::cast(s->klass())->element_type()], | 
|---|
| 126 | type2name_tab[ArrayKlass::cast(d->klass())->element_type()]); | 
|---|
| 127 | THROW_MSG(vmSymbols::java_lang_ArrayStoreException(), ss.as_string()); | 
|---|
| 128 | } | 
|---|
| 129 |  | 
|---|
| 130 | // Check if all offsets and lengths are non negative. | 
|---|
| 131 | if (src_pos < 0 || dst_pos < 0 || length < 0) { | 
|---|
| 132 | // Pass specific exception reason. | 
|---|
| 133 | ResourceMark rm(THREAD); | 
|---|
| 134 | stringStream ss; | 
|---|
| 135 | if (src_pos < 0) { | 
|---|
| 136 | ss.print( "arraycopy: source index %d out of bounds for %s[%d]", | 
|---|
| 137 | src_pos, type2name_tab[ArrayKlass::cast(s->klass())->element_type()], s->length()); | 
|---|
| 138 | } else if (dst_pos < 0) { | 
|---|
| 139 | ss.print( "arraycopy: destination index %d out of bounds for %s[%d]", | 
|---|
| 140 | dst_pos, type2name_tab[ArrayKlass::cast(d->klass())->element_type()], d->length()); | 
|---|
| 141 | } else { | 
|---|
| 142 | ss.print( "arraycopy: length %d is negative", length); | 
|---|
| 143 | } | 
|---|
| 144 | THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string()); | 
|---|
| 145 | } | 
|---|
| 146 | // Check if the ranges are valid | 
|---|
| 147 | if ((((unsigned int) length + (unsigned int) src_pos) > (unsigned int) s->length()) || | 
|---|
| 148 | (((unsigned int) length + (unsigned int) dst_pos) > (unsigned int) d->length())) { | 
|---|
| 149 | // Pass specific exception reason. | 
|---|
| 150 | ResourceMark rm(THREAD); | 
|---|
| 151 | stringStream ss; | 
|---|
| 152 | if (((unsigned int) length + (unsigned int) src_pos) > (unsigned int) s->length()) { | 
|---|
| 153 | ss.print( "arraycopy: last source index %u out of bounds for %s[%d]", | 
|---|
| 154 | (unsigned int) length + (unsigned int) src_pos, | 
|---|
| 155 | type2name_tab[ArrayKlass::cast(s->klass())->element_type()], s->length()); | 
|---|
| 156 | } else { | 
|---|
| 157 | ss.print( "arraycopy: last destination index %u out of bounds for %s[%d]", | 
|---|
| 158 | (unsigned int) length + (unsigned int) dst_pos, | 
|---|
| 159 | type2name_tab[ArrayKlass::cast(d->klass())->element_type()], d->length()); | 
|---|
| 160 | } | 
|---|
| 161 | THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string()); | 
|---|
| 162 | } | 
|---|
| 163 | // Check zero copy | 
|---|
| 164 | if (length == 0) | 
|---|
| 165 | return; | 
|---|
| 166 |  | 
|---|
| 167 | // This is an attempt to make the copy_array fast. | 
|---|
| 168 | int l2es = log2_element_size(); | 
|---|
| 169 | size_t src_offset = arrayOopDesc::base_offset_in_bytes(element_type()) + ((size_t)src_pos << l2es); | 
|---|
| 170 | size_t dst_offset = arrayOopDesc::base_offset_in_bytes(element_type()) + ((size_t)dst_pos << l2es); | 
|---|
| 171 | ArrayAccess<ARRAYCOPY_ATOMIC>::arraycopy<void>(s, src_offset, d, dst_offset, (size_t)length << l2es); | 
|---|
| 172 | } | 
|---|
| 173 |  | 
|---|
| 174 | // create a klass of array holding typeArrays | 
|---|
| 175 | Klass* TypeArrayKlass::array_klass_impl(bool or_null, int n, TRAPS) { | 
|---|
| 176 | int dim = dimension(); | 
|---|
| 177 | assert(dim <= n, "check order of chain"); | 
|---|
| 178 | if (dim == n) | 
|---|
| 179 | return this; | 
|---|
| 180 |  | 
|---|
| 181 | // lock-free read needs acquire semantics | 
|---|
| 182 | if (higher_dimension_acquire() == NULL) { | 
|---|
| 183 | if (or_null)  return NULL; | 
|---|
| 184 |  | 
|---|
| 185 | ResourceMark rm; | 
|---|
| 186 | JavaThread *jt = (JavaThread *)THREAD; | 
|---|
| 187 | { | 
|---|
| 188 | // Atomic create higher dimension and link into list | 
|---|
| 189 | MutexLocker mu(MultiArray_lock, THREAD); | 
|---|
| 190 |  | 
|---|
| 191 | if (higher_dimension() == NULL) { | 
|---|
| 192 | Klass* oak = ObjArrayKlass::allocate_objArray_klass( | 
|---|
| 193 | class_loader_data(), dim + 1, this, CHECK_NULL); | 
|---|
| 194 | ObjArrayKlass* h_ak = ObjArrayKlass::cast(oak); | 
|---|
| 195 | h_ak->set_lower_dimension(this); | 
|---|
| 196 | // use 'release' to pair with lock-free load | 
|---|
| 197 | release_set_higher_dimension(h_ak); | 
|---|
| 198 | assert(h_ak->is_objArray_klass(), "incorrect initialization of ObjArrayKlass"); | 
|---|
| 199 | } | 
|---|
| 200 | } | 
|---|
| 201 | } else { | 
|---|
| 202 | CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops()); | 
|---|
| 203 | } | 
|---|
| 204 | ObjArrayKlass* h_ak = ObjArrayKlass::cast(higher_dimension()); | 
|---|
| 205 | if (or_null) { | 
|---|
| 206 | return h_ak->array_klass_or_null(n); | 
|---|
| 207 | } | 
|---|
| 208 | return h_ak->array_klass(n, THREAD); | 
|---|
| 209 | } | 
|---|
| 210 |  | 
|---|
| 211 | Klass* TypeArrayKlass::array_klass_impl(bool or_null, TRAPS) { | 
|---|
| 212 | return array_klass_impl(or_null, dimension() +  1, THREAD); | 
|---|
| 213 | } | 
|---|
| 214 |  | 
|---|
| 215 | int TypeArrayKlass::oop_size(oop obj) const { | 
|---|
| 216 | assert(obj->is_typeArray(), "must be a type array"); | 
|---|
| 217 | typeArrayOop t = typeArrayOop(obj); | 
|---|
| 218 | return t->object_size(); | 
|---|
| 219 | } | 
|---|
| 220 |  | 
|---|
| 221 | void TypeArrayKlass::initialize(TRAPS) { | 
|---|
| 222 | // Nothing to do. Having this function is handy since objArrayKlasses can be | 
|---|
| 223 | // initialized by calling initialize on their bottom_klass, see ObjArrayKlass::initialize | 
|---|
| 224 | } | 
|---|
| 225 |  | 
|---|
| 226 | const char* TypeArrayKlass::external_name(BasicType type) { | 
|---|
| 227 | switch (type) { | 
|---|
| 228 | case T_BOOLEAN: return "[Z"; | 
|---|
| 229 | case T_CHAR:    return "[C"; | 
|---|
| 230 | case T_FLOAT:   return "[F"; | 
|---|
| 231 | case T_DOUBLE:  return "[D"; | 
|---|
| 232 | case T_BYTE:    return "[B"; | 
|---|
| 233 | case T_SHORT:   return "[S"; | 
|---|
| 234 | case T_INT:     return "[I"; | 
|---|
| 235 | case T_LONG:    return "[J"; | 
|---|
| 236 | default: ShouldNotReachHere(); | 
|---|
| 237 | } | 
|---|
| 238 | return NULL; | 
|---|
| 239 | } | 
|---|
| 240 |  | 
|---|
| 241 |  | 
|---|
| 242 | // Printing | 
|---|
| 243 |  | 
|---|
| 244 | void TypeArrayKlass::print_on(outputStream* st) const { | 
|---|
| 245 | #ifndef PRODUCT | 
|---|
| 246 | assert(is_klass(), "must be klass"); | 
|---|
| 247 | print_value_on(st); | 
|---|
| 248 | Klass::print_on(st); | 
|---|
| 249 | #endif //PRODUCT | 
|---|
| 250 | } | 
|---|
| 251 |  | 
|---|
| 252 | void TypeArrayKlass::print_value_on(outputStream* st) const { | 
|---|
| 253 | assert(is_klass(), "must be klass"); | 
|---|
| 254 | st->print( "{type array "); | 
|---|
| 255 | BasicType bt = element_type(); | 
|---|
| 256 | if (bt == T_BOOLEAN) { | 
|---|
| 257 | st->print( "bool"); | 
|---|
| 258 | } else { | 
|---|
| 259 | st->print( "%s", type2name_tab[bt]); | 
|---|
| 260 | } | 
|---|
| 261 | st->print( "}"); | 
|---|
| 262 | } | 
|---|
| 263 |  | 
|---|
| 264 | #ifndef PRODUCT | 
|---|
| 265 |  | 
|---|
| 266 | static void print_boolean_array(typeArrayOop ta, int print_len, outputStream* st) { | 
|---|
| 267 | for (int index = 0; index < print_len; index++) { | 
|---|
| 268 | st->print_cr( " - %3d: %s", index, (ta->bool_at(index) == 0) ? "false": "true"); | 
|---|
| 269 | } | 
|---|
| 270 | } | 
|---|
| 271 |  | 
|---|
| 272 |  | 
|---|
| 273 | static void print_char_array(typeArrayOop ta, int print_len, outputStream* st) { | 
|---|
| 274 | for (int index = 0; index < print_len; index++) { | 
|---|
| 275 | jchar c = ta->char_at(index); | 
|---|
| 276 | st->print_cr( " - %3d: %x %c", index, c, isprint(c) ? c : ' '); | 
|---|
| 277 | } | 
|---|
| 278 | } | 
|---|
| 279 |  | 
|---|
| 280 |  | 
|---|
| 281 | static void print_float_array(typeArrayOop ta, int print_len, outputStream* st) { | 
|---|
| 282 | for (int index = 0; index < print_len; index++) { | 
|---|
| 283 | st->print_cr( " - %3d: %g", index, ta->float_at(index)); | 
|---|
| 284 | } | 
|---|
| 285 | } | 
|---|
| 286 |  | 
|---|
| 287 |  | 
|---|
| 288 | static void print_double_array(typeArrayOop ta, int print_len, outputStream* st) { | 
|---|
| 289 | for (int index = 0; index < print_len; index++) { | 
|---|
| 290 | st->print_cr( " - %3d: %g", index, ta->double_at(index)); | 
|---|
| 291 | } | 
|---|
| 292 | } | 
|---|
| 293 |  | 
|---|
| 294 |  | 
|---|
| 295 | static void print_byte_array(typeArrayOop ta, int print_len, outputStream* st) { | 
|---|
| 296 | for (int index = 0; index < print_len; index++) { | 
|---|
| 297 | jbyte c = ta->byte_at(index); | 
|---|
| 298 | st->print_cr( " - %3d: %x %c", index, c, isprint(c) ? c : ' '); | 
|---|
| 299 | } | 
|---|
| 300 | } | 
|---|
| 301 |  | 
|---|
| 302 |  | 
|---|
| 303 | static void print_short_array(typeArrayOop ta, int print_len, outputStream* st) { | 
|---|
| 304 | for (int index = 0; index < print_len; index++) { | 
|---|
| 305 | int v = ta->ushort_at(index); | 
|---|
| 306 | st->print_cr( " - %3d: 0x%x\t %d", index, v, v); | 
|---|
| 307 | } | 
|---|
| 308 | } | 
|---|
| 309 |  | 
|---|
| 310 |  | 
|---|
| 311 | static void print_int_array(typeArrayOop ta, int print_len, outputStream* st) { | 
|---|
| 312 | for (int index = 0; index < print_len; index++) { | 
|---|
| 313 | jint v = ta->int_at(index); | 
|---|
| 314 | st->print_cr( " - %3d: 0x%x %d", index, v, v); | 
|---|
| 315 | } | 
|---|
| 316 | } | 
|---|
| 317 |  | 
|---|
| 318 |  | 
|---|
| 319 | static void print_long_array(typeArrayOop ta, int print_len, outputStream* st) { | 
|---|
| 320 | for (int index = 0; index < print_len; index++) { | 
|---|
| 321 | jlong v = ta->long_at(index); | 
|---|
| 322 | st->print_cr( " - %3d: 0x%x 0x%x", index, high(v), low(v)); | 
|---|
| 323 | } | 
|---|
| 324 | } | 
|---|
| 325 |  | 
|---|
| 326 |  | 
|---|
| 327 | void TypeArrayKlass::oop_print_on(oop obj, outputStream* st) { | 
|---|
| 328 | ArrayKlass::oop_print_on(obj, st); | 
|---|
| 329 | typeArrayOop ta = typeArrayOop(obj); | 
|---|
| 330 | int print_len = MIN2((intx) ta->length(), MaxElementPrintSize); | 
|---|
| 331 | switch (element_type()) { | 
|---|
| 332 | case T_BOOLEAN: print_boolean_array(ta, print_len, st); break; | 
|---|
| 333 | case T_CHAR:    print_char_array(ta, print_len, st);    break; | 
|---|
| 334 | case T_FLOAT:   print_float_array(ta, print_len, st);   break; | 
|---|
| 335 | case T_DOUBLE:  print_double_array(ta, print_len, st);  break; | 
|---|
| 336 | case T_BYTE:    print_byte_array(ta, print_len, st);    break; | 
|---|
| 337 | case T_SHORT:   print_short_array(ta, print_len, st);   break; | 
|---|
| 338 | case T_INT:     print_int_array(ta, print_len, st);     break; | 
|---|
| 339 | case T_LONG:    print_long_array(ta, print_len, st);    break; | 
|---|
| 340 | default: ShouldNotReachHere(); | 
|---|
| 341 | } | 
|---|
| 342 | int remaining = ta->length() - print_len; | 
|---|
| 343 | if (remaining > 0) { | 
|---|
| 344 | st->print_cr( " - <%d more elements, increase MaxElementPrintSize to print>", remaining); | 
|---|
| 345 | } | 
|---|
| 346 | } | 
|---|
| 347 |  | 
|---|
| 348 | #endif // PRODUCT | 
|---|
| 349 |  | 
|---|
| 350 | const char* TypeArrayKlass::internal_name() const { | 
|---|
| 351 | return Klass::external_name(); | 
|---|
| 352 | } | 
|---|
| 353 |  | 
|---|
| 354 | // A TypeArrayKlass is an array of a primitive type, its defining module is java.base | 
|---|
| 355 | ModuleEntry* TypeArrayKlass::module() const { | 
|---|
| 356 | return ModuleEntryTable::javabase_moduleEntry(); | 
|---|
| 357 | } | 
|---|
| 358 |  | 
|---|
| 359 | PackageEntry* TypeArrayKlass::package() const { | 
|---|
| 360 | return NULL; | 
|---|
| 361 | } | 
|---|
| 362 |  | 
|---|