Thu, 07 Apr 2011 09:53:20 -0700
7009266: G1: assert(obj->is_oop_or_null(true )) failed: Error
Summary: A referent object that is only weakly reachable at the start of concurrent marking but is re-attached to the strongly reachable object graph during marking may not be marked as live. This can cause the reference object to be processed prematurely and leave dangling pointers to the referent object. Implement a read barrier for the java.lang.ref.Reference::referent field by intrinsifying the Reference.get() method, and intercepting accesses though JNI, reflection, and Unsafe, so that when a non-null referent object is read it is also logged in an SATB buffer.
Reviewed-by: kvn, iveresov, never, tonyp, dholmes
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 */
25 #include "precompiled.hpp"
26 #include "classfile/systemDictionary.hpp"
27 #include "classfile/vmSymbols.hpp"
28 #include "gc_interface/collectedHeap.hpp"
29 #include "gc_interface/collectedHeap.inline.hpp"
30 #include "memory/resourceArea.hpp"
31 #include "memory/universe.hpp"
32 #include "memory/universe.inline.hpp"
33 #include "oops/instanceKlass.hpp"
34 #include "oops/klassOop.hpp"
35 #include "oops/objArrayKlassKlass.hpp"
36 #include "oops/oop.inline.hpp"
37 #include "oops/typeArrayKlass.hpp"
38 #include "oops/typeArrayOop.hpp"
39 #include "runtime/handles.inline.hpp"
41 bool typeArrayKlass::compute_is_subtype_of(klassOop k) {
42 if (!k->klass_part()->oop_is_typeArray()) {
43 return arrayKlass::compute_is_subtype_of(k);
44 }
46 typeArrayKlass* tak = typeArrayKlass::cast(k);
47 if (dimension() != tak->dimension()) return false;
49 return element_type() == tak->element_type();
50 }
52 klassOop typeArrayKlass::create_klass(BasicType type, int scale,
53 const char* name_str, TRAPS) {
54 typeArrayKlass o;
56 Symbol* sym = NULL;
57 if (name_str != NULL) {
58 sym = SymbolTable::new_symbol(name_str, CHECK_NULL);
59 }
60 KlassHandle klassklass (THREAD, Universe::typeArrayKlassKlassObj());
62 arrayKlassHandle k = base_create_array_klass(o.vtbl_value(), header_size(), klassklass, CHECK_NULL);
63 typeArrayKlass* ak = typeArrayKlass::cast(k());
64 ak->set_name(sym);
65 ak->set_layout_helper(array_layout_helper(type));
66 assert(scale == (1 << ak->log2_element_size()), "scale must check out");
67 assert(ak->oop_is_javaArray(), "sanity");
68 assert(ak->oop_is_typeArray(), "sanity");
69 ak->set_max_length(arrayOopDesc::max_array_length(type));
70 assert(k()->size() > header_size(), "bad size");
72 // Call complete_create_array_klass after all instance variables have been initialized.
73 KlassHandle super (THREAD, k->super());
74 complete_create_array_klass(k, super, CHECK_NULL);
76 return k();
77 }
79 typeArrayOop typeArrayKlass::allocate(int length, TRAPS) {
80 assert(log2_element_size() >= 0, "bad scale");
81 if (length >= 0) {
82 if (length <= max_length()) {
83 size_t size = typeArrayOopDesc::object_size(layout_helper(), length);
84 KlassHandle h_k(THREAD, as_klassOop());
85 typeArrayOop t;
86 CollectedHeap* ch = Universe::heap();
87 if (size < ch->large_typearray_limit()) {
88 t = (typeArrayOop)CollectedHeap::array_allocate(h_k, (int)size, length, CHECK_NULL);
89 } else {
90 t = (typeArrayOop)CollectedHeap::large_typearray_allocate(h_k, (int)size, length, CHECK_NULL);
91 }
92 assert(t->is_parsable(), "Don't publish unless parsable");
93 return t;
94 } else {
95 report_java_out_of_memory("Requested array size exceeds VM limit");
96 THROW_OOP_0(Universe::out_of_memory_error_array_size());
97 }
98 } else {
99 THROW_0(vmSymbols::java_lang_NegativeArraySizeException());
100 }
101 }
103 typeArrayOop typeArrayKlass::allocate_permanent(int length, TRAPS) {
104 if (length < 0) THROW_0(vmSymbols::java_lang_NegativeArraySizeException());
105 int size = typeArrayOopDesc::object_size(layout_helper(), length);
106 KlassHandle h_k(THREAD, as_klassOop());
107 typeArrayOop t = (typeArrayOop)
108 CollectedHeap::permanent_array_allocate(h_k, size, length, CHECK_NULL);
109 assert(t->is_parsable(), "Can't publish until parsable");
110 return t;
111 }
113 oop typeArrayKlass::multi_allocate(int rank, jint* last_size, TRAPS) {
114 // For typeArrays this is only called for the last dimension
115 assert(rank == 1, "just checking");
116 int length = *last_size;
117 return allocate(length, THREAD);
118 }
121 void typeArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d, int dst_pos, int length, TRAPS) {
122 assert(s->is_typeArray(), "must be type array");
124 // Check destination
125 if (!d->is_typeArray() || element_type() != typeArrayKlass::cast(d->klass())->element_type()) {
126 THROW(vmSymbols::java_lang_ArrayStoreException());
127 }
129 // Check is all offsets and lengths are non negative
130 if (src_pos < 0 || dst_pos < 0 || length < 0) {
131 THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException());
132 }
133 // Check if the ranges are valid
134 if ( (((unsigned int) length + (unsigned int) src_pos) > (unsigned int) s->length())
135 || (((unsigned int) length + (unsigned int) dst_pos) > (unsigned int) d->length()) ) {
136 THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException());
137 }
138 // Check zero copy
139 if (length == 0)
140 return;
142 // This is an attempt to make the copy_array fast.
143 int l2es = log2_element_size();
144 int ihs = array_header_in_bytes() / wordSize;
145 char* src = (char*) ((oop*)s + ihs) + ((size_t)src_pos << l2es);
146 char* dst = (char*) ((oop*)d + ihs) + ((size_t)dst_pos << l2es);
147 Copy::conjoint_memory_atomic(src, dst, (size_t)length << l2es);
148 }
151 // create a klass of array holding typeArrays
152 klassOop typeArrayKlass::array_klass_impl(bool or_null, int n, TRAPS) {
153 typeArrayKlassHandle h_this(THREAD, as_klassOop());
154 return array_klass_impl(h_this, or_null, n, THREAD);
155 }
157 klassOop typeArrayKlass::array_klass_impl(typeArrayKlassHandle h_this, bool or_null, int n, TRAPS) {
158 int dimension = h_this->dimension();
159 assert(dimension <= n, "check order of chain");
160 if (dimension == n)
161 return h_this();
163 objArrayKlassHandle h_ak(THREAD, h_this->higher_dimension());
164 if (h_ak.is_null()) {
165 if (or_null) return NULL;
167 ResourceMark rm;
168 JavaThread *jt = (JavaThread *)THREAD;
169 {
170 MutexLocker mc(Compile_lock, THREAD); // for vtables
171 // Atomic create higher dimension and link into list
172 MutexLocker mu(MultiArray_lock, THREAD);
174 h_ak = objArrayKlassHandle(THREAD, h_this->higher_dimension());
175 if (h_ak.is_null()) {
176 klassOop oak = objArrayKlassKlass::cast(
177 Universe::objArrayKlassKlassObj())->allocate_objArray_klass(
178 dimension + 1, h_this, CHECK_NULL);
179 h_ak = objArrayKlassHandle(THREAD, oak);
180 h_ak->set_lower_dimension(h_this());
181 OrderAccess::storestore();
182 h_this->set_higher_dimension(h_ak());
183 assert(h_ak->oop_is_objArray(), "incorrect initialization of objArrayKlass");
184 }
185 }
186 } else {
187 CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
188 }
189 if (or_null) {
190 return h_ak->array_klass_or_null(n);
191 }
192 return h_ak->array_klass(n, CHECK_NULL);
193 }
195 klassOop typeArrayKlass::array_klass_impl(bool or_null, TRAPS) {
196 return array_klass_impl(or_null, dimension() + 1, THREAD);
197 }
199 int typeArrayKlass::oop_size(oop obj) const {
200 assert(obj->is_typeArray(),"must be a type array");
201 typeArrayOop t = typeArrayOop(obj);
202 return t->object_size();
203 }
205 void typeArrayKlass::oop_follow_contents(oop obj) {
206 assert(obj->is_typeArray(),"must be a type array");
207 // Performance tweak: We skip iterating over the klass pointer since we
208 // know that Universe::typeArrayKlass never moves.
209 }
211 #ifndef SERIALGC
212 void typeArrayKlass::oop_follow_contents(ParCompactionManager* cm, oop obj) {
213 assert(obj->is_typeArray(),"must be a type array");
214 // Performance tweak: We skip iterating over the klass pointer since we
215 // know that Universe::typeArrayKlass never moves.
216 }
217 #endif // SERIALGC
219 int typeArrayKlass::oop_adjust_pointers(oop obj) {
220 assert(obj->is_typeArray(),"must be a type array");
221 typeArrayOop t = typeArrayOop(obj);
222 // Performance tweak: We skip iterating over the klass pointer since we
223 // know that Universe::typeArrayKlass never moves.
224 return t->object_size();
225 }
227 int typeArrayKlass::oop_oop_iterate(oop obj, OopClosure* blk) {
228 assert(obj->is_typeArray(),"must be a type array");
229 typeArrayOop t = typeArrayOop(obj);
230 // Performance tweak: We skip iterating over the klass pointer since we
231 // know that Universe::typeArrayKlass never moves.
232 return t->object_size();
233 }
235 int typeArrayKlass::oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr) {
236 assert(obj->is_typeArray(),"must be a type array");
237 typeArrayOop t = typeArrayOop(obj);
238 // Performance tweak: We skip iterating over the klass pointer since we
239 // know that Universe::typeArrayKlass never moves.
240 return t->object_size();
241 }
243 #ifndef SERIALGC
244 void typeArrayKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
245 assert(obj->is_typeArray(),"must be a type array");
246 }
248 int
249 typeArrayKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) {
250 assert(obj->is_typeArray(),"must be a type array");
251 return typeArrayOop(obj)->object_size();
252 }
253 #endif // SERIALGC
255 void typeArrayKlass::initialize(TRAPS) {
256 // Nothing to do. Having this function is handy since objArrayKlasses can be
257 // initialized by calling initialize on their bottom_klass, see objArrayKlass::initialize
258 }
260 const char* typeArrayKlass::external_name(BasicType type) {
261 switch (type) {
262 case T_BOOLEAN: return "[Z";
263 case T_CHAR: return "[C";
264 case T_FLOAT: return "[F";
265 case T_DOUBLE: return "[D";
266 case T_BYTE: return "[B";
267 case T_SHORT: return "[S";
268 case T_INT: return "[I";
269 case T_LONG: return "[J";
270 default: ShouldNotReachHere();
271 }
272 return NULL;
273 }
275 #ifndef PRODUCT
276 // Printing
278 static void print_boolean_array(typeArrayOop ta, int print_len, outputStream* st) {
279 for (int index = 0; index < print_len; index++) {
280 st->print_cr(" - %3d: %s", index, (ta->bool_at(index) == 0) ? "false" : "true");
281 }
282 }
285 static void print_char_array(typeArrayOop ta, int print_len, outputStream* st) {
286 for (int index = 0; index < print_len; index++) {
287 jchar c = ta->char_at(index);
288 st->print_cr(" - %3d: %x %c", index, c, isprint(c) ? c : ' ');
289 }
290 }
293 static void print_float_array(typeArrayOop ta, int print_len, outputStream* st) {
294 for (int index = 0; index < print_len; index++) {
295 st->print_cr(" - %3d: %g", index, ta->float_at(index));
296 }
297 }
300 static void print_double_array(typeArrayOop ta, int print_len, outputStream* st) {
301 for (int index = 0; index < print_len; index++) {
302 st->print_cr(" - %3d: %g", index, ta->double_at(index));
303 }
304 }
307 static void print_byte_array(typeArrayOop ta, int print_len, outputStream* st) {
308 for (int index = 0; index < print_len; index++) {
309 jbyte c = ta->byte_at(index);
310 st->print_cr(" - %3d: %x %c", index, c, isprint(c) ? c : ' ');
311 }
312 }
315 static void print_short_array(typeArrayOop ta, int print_len, outputStream* st) {
316 for (int index = 0; index < print_len; index++) {
317 int v = ta->ushort_at(index);
318 st->print_cr(" - %3d: 0x%x\t %d", index, v, v);
319 }
320 }
323 static void print_int_array(typeArrayOop ta, int print_len, outputStream* st) {
324 for (int index = 0; index < print_len; index++) {
325 jint v = ta->int_at(index);
326 st->print_cr(" - %3d: 0x%x %d", index, v, v);
327 }
328 }
331 static void print_long_array(typeArrayOop ta, int print_len, outputStream* st) {
332 for (int index = 0; index < print_len; index++) {
333 jlong v = ta->long_at(index);
334 st->print_cr(" - %3d: 0x%x 0x%x", index, high(v), low(v));
335 }
336 }
339 void typeArrayKlass::oop_print_on(oop obj, outputStream* st) {
340 arrayKlass::oop_print_on(obj, st);
341 typeArrayOop ta = typeArrayOop(obj);
342 int print_len = MIN2((intx) ta->length(), MaxElementPrintSize);
343 switch (element_type()) {
344 case T_BOOLEAN: print_boolean_array(ta, print_len, st); break;
345 case T_CHAR: print_char_array(ta, print_len, st); break;
346 case T_FLOAT: print_float_array(ta, print_len, st); break;
347 case T_DOUBLE: print_double_array(ta, print_len, st); break;
348 case T_BYTE: print_byte_array(ta, print_len, st); break;
349 case T_SHORT: print_short_array(ta, print_len, st); break;
350 case T_INT: print_int_array(ta, print_len, st); break;
351 case T_LONG: print_long_array(ta, print_len, st); break;
352 default: ShouldNotReachHere();
353 }
354 int remaining = ta->length() - print_len;
355 if (remaining > 0) {
356 tty->print_cr(" - <%d more elements, increase MaxElementPrintSize to print>", remaining);
357 }
358 }
360 #endif // PRODUCT
362 const char* typeArrayKlass::internal_name() const {
363 return Klass::external_name();
364 }