Mercurial > hg > graal-jvmci-8
comparison src/cpu/sparc/vm/assembler_sparc.cpp @ 3249:e1162778c1c8
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
author | johnc |
---|---|
date | Thu, 07 Apr 2011 09:53:20 -0700 |
parents | 8033953d67ff |
children | f7d55ea6ee56 |
comparison
equal
deleted
inserted
replaced
3248:e6beb62de02d | 3249:e1162778c1c8 |
---|---|
4255 } | 4255 } |
4256 | 4256 |
4257 /////////////////////////////////////////////////////////////////////////////////// | 4257 /////////////////////////////////////////////////////////////////////////////////// |
4258 #ifndef SERIALGC | 4258 #ifndef SERIALGC |
4259 | 4259 |
4260 static uint num_stores = 0; | 4260 static address satb_log_enqueue_with_frame = NULL; |
4261 static uint num_null_pre_stores = 0; | 4261 static u_char* satb_log_enqueue_with_frame_end = NULL; |
4262 | 4262 |
4263 static void count_null_pre_vals(void* pre_val) { | 4263 static address satb_log_enqueue_frameless = NULL; |
4264 num_stores++; | 4264 static u_char* satb_log_enqueue_frameless_end = NULL; |
4265 if (pre_val == NULL) num_null_pre_stores++; | |
4266 if ((num_stores % 1000000) == 0) { | |
4267 tty->print_cr(UINT32_FORMAT " stores, " UINT32_FORMAT " (%5.2f%%) with null pre-vals.", | |
4268 num_stores, num_null_pre_stores, | |
4269 100.0*(float)num_null_pre_stores/(float)num_stores); | |
4270 } | |
4271 } | |
4272 | |
4273 static address satb_log_enqueue_with_frame = 0; | |
4274 static u_char* satb_log_enqueue_with_frame_end = 0; | |
4275 | |
4276 static address satb_log_enqueue_frameless = 0; | |
4277 static u_char* satb_log_enqueue_frameless_end = 0; | |
4278 | 4265 |
4279 static int EnqueueCodeSize = 128 DEBUG_ONLY( + 256); // Instructions? | 4266 static int EnqueueCodeSize = 128 DEBUG_ONLY( + 256); // Instructions? |
4280 | |
4281 // The calls to this don't work. We'd need to do a fair amount of work to | |
4282 // make it work. | |
4283 static void check_index(int ind) { | |
4284 assert(0 <= ind && ind <= 64*K && ((ind % oopSize) == 0), | |
4285 "Invariants."); | |
4286 } | |
4287 | 4267 |
4288 static void generate_satb_log_enqueue(bool with_frame) { | 4268 static void generate_satb_log_enqueue(bool with_frame) { |
4289 BufferBlob* bb = BufferBlob::create("enqueue_with_frame", EnqueueCodeSize); | 4269 BufferBlob* bb = BufferBlob::create("enqueue_with_frame", EnqueueCodeSize); |
4290 CodeBuffer buf(bb); | 4270 CodeBuffer buf(bb); |
4291 MacroAssembler masm(&buf); | 4271 MacroAssembler masm(&buf); |
4386 } | 4366 } |
4387 } | 4367 } |
4388 } | 4368 } |
4389 } | 4369 } |
4390 | 4370 |
4391 void MacroAssembler::g1_write_barrier_pre(Register obj, Register index, int offset, Register tmp, bool preserve_o_regs) { | 4371 void MacroAssembler::g1_write_barrier_pre(Register obj, |
4392 assert(offset == 0 || index == noreg, "choose one"); | 4372 Register index, |
4393 | 4373 int offset, |
4394 if (G1DisablePreBarrier) return; | 4374 Register pre_val, |
4395 // satb_log_barrier(tmp, obj, offset, preserve_o_regs); | 4375 Register tmp, |
4376 bool preserve_o_regs) { | |
4396 Label filtered; | 4377 Label filtered; |
4397 // satb_log_barrier_work0(tmp, filtered); | 4378 |
4379 if (obj == noreg) { | |
4380 // We are not loading the previous value so make | |
4381 // sure that we don't trash the value in pre_val | |
4382 // with the code below. | |
4383 assert_different_registers(pre_val, tmp); | |
4384 } else { | |
4385 // We will be loading the previous value | |
4386 // in this code so... | |
4387 assert(offset == 0 || index == noreg, "choose one"); | |
4388 assert(pre_val == noreg, "check this code"); | |
4389 } | |
4390 | |
4391 // Is marking active? | |
4398 if (in_bytes(PtrQueue::byte_width_of_active()) == 4) { | 4392 if (in_bytes(PtrQueue::byte_width_of_active()) == 4) { |
4399 ld(G2, | 4393 ld(G2, |
4400 in_bytes(JavaThread::satb_mark_queue_offset() + | 4394 in_bytes(JavaThread::satb_mark_queue_offset() + |
4401 PtrQueue::byte_offset_of_active()), | 4395 PtrQueue::byte_offset_of_active()), |
4402 tmp); | 4396 tmp); |
4411 | 4405 |
4412 // Check on whether to annul. | 4406 // Check on whether to annul. |
4413 br_on_reg_cond(rc_z, /*annul*/false, Assembler::pt, tmp, filtered); | 4407 br_on_reg_cond(rc_z, /*annul*/false, Assembler::pt, tmp, filtered); |
4414 delayed() -> nop(); | 4408 delayed() -> nop(); |
4415 | 4409 |
4416 // satb_log_barrier_work1(tmp, offset); | 4410 // Do we need to load the previous value? |
4417 if (index == noreg) { | 4411 if (obj != noreg) { |
4418 if (Assembler::is_simm13(offset)) { | 4412 // Load the previous value... |
4419 load_heap_oop(obj, offset, tmp); | 4413 if (index == noreg) { |
4414 if (Assembler::is_simm13(offset)) { | |
4415 load_heap_oop(obj, offset, tmp); | |
4416 } else { | |
4417 set(offset, tmp); | |
4418 load_heap_oop(obj, tmp, tmp); | |
4419 } | |
4420 } else { | 4420 } else { |
4421 set(offset, tmp); | 4421 load_heap_oop(obj, index, tmp); |
4422 load_heap_oop(obj, tmp, tmp); | |
4423 } | 4422 } |
4424 } else { | 4423 // Previous value has been loaded into tmp |
4425 load_heap_oop(obj, index, tmp); | 4424 pre_val = tmp; |
4426 } | 4425 } |
4427 | 4426 |
4428 // satb_log_barrier_work2(obj, tmp, offset); | 4427 assert(pre_val != noreg, "must have a real register"); |
4429 | 4428 |
4430 // satb_log_barrier_work3(tmp, filtered, preserve_o_regs); | 4429 // Is the previous value null? |
4431 | |
4432 const Register pre_val = tmp; | |
4433 | |
4434 if (G1SATBBarrierPrintNullPreVals) { | |
4435 save_frame(0); | |
4436 mov(pre_val, O0); | |
4437 // Save G-regs that target may use. | |
4438 mov(G1, L1); | |
4439 mov(G2, L2); | |
4440 mov(G3, L3); | |
4441 mov(G4, L4); | |
4442 mov(G5, L5); | |
4443 call(CAST_FROM_FN_PTR(address, &count_null_pre_vals)); | |
4444 delayed()->nop(); | |
4445 // Restore G-regs that target may have used. | |
4446 mov(L1, G1); | |
4447 mov(L2, G2); | |
4448 mov(L3, G3); | |
4449 mov(L4, G4); | |
4450 mov(L5, G5); | |
4451 restore(G0, G0, G0); | |
4452 } | |
4453 | |
4454 // Check on whether to annul. | 4430 // Check on whether to annul. |
4455 br_on_reg_cond(rc_z, /*annul*/false, Assembler::pt, pre_val, filtered); | 4431 br_on_reg_cond(rc_z, /*annul*/false, Assembler::pt, pre_val, filtered); |
4456 delayed() -> nop(); | 4432 delayed() -> nop(); |
4457 | 4433 |
4458 // OK, it's not filtered, so we'll need to call enqueue. In the normal | 4434 // OK, it's not filtered, so we'll need to call enqueue. In the normal |
4459 // case, pre_val will be a scratch G-reg, but there's some cases in which | 4435 // case, pre_val will be a scratch G-reg, but there are some cases in |
4460 // it's an O-reg. In the first case, do a normal call. In the latter, | 4436 // which it's an O-reg. In the first case, do a normal call. In the |
4461 // do a save here and call the frameless version. | 4437 // latter, do a save here and call the frameless version. |
4462 | 4438 |
4463 guarantee(pre_val->is_global() || pre_val->is_out(), | 4439 guarantee(pre_val->is_global() || pre_val->is_out(), |
4464 "Or we need to think harder."); | 4440 "Or we need to think harder."); |
4441 | |
4465 if (pre_val->is_global() && !preserve_o_regs) { | 4442 if (pre_val->is_global() && !preserve_o_regs) { |
4466 generate_satb_log_enqueue_if_necessary(true); // with frame. | 4443 generate_satb_log_enqueue_if_necessary(true); // with frame |
4444 | |
4467 call(satb_log_enqueue_with_frame); | 4445 call(satb_log_enqueue_with_frame); |
4468 delayed()->mov(pre_val, O0); | 4446 delayed()->mov(pre_val, O0); |
4469 } else { | 4447 } else { |
4470 generate_satb_log_enqueue_if_necessary(false); // with frameless. | 4448 generate_satb_log_enqueue_if_necessary(false); // frameless |
4449 | |
4471 save_frame(0); | 4450 save_frame(0); |
4472 call(satb_log_enqueue_frameless); | 4451 call(satb_log_enqueue_frameless); |
4473 delayed()->mov(pre_val->after_save(), O0); | 4452 delayed()->mov(pre_val->after_save(), O0); |
4474 restore(); | 4453 restore(); |
4475 } | 4454 } |
4612 | 4591 |
4613 Label filtered; | 4592 Label filtered; |
4614 MacroAssembler* post_filter_masm = this; | 4593 MacroAssembler* post_filter_masm = this; |
4615 | 4594 |
4616 if (new_val == G0) return; | 4595 if (new_val == G0) return; |
4617 if (G1DisablePostBarrier) return; | |
4618 | 4596 |
4619 G1SATBCardTableModRefBS* bs = (G1SATBCardTableModRefBS*) Universe::heap()->barrier_set(); | 4597 G1SATBCardTableModRefBS* bs = (G1SATBCardTableModRefBS*) Universe::heap()->barrier_set(); |
4620 assert(bs->kind() == BarrierSet::G1SATBCT || | 4598 assert(bs->kind() == BarrierSet::G1SATBCT || |
4621 bs->kind() == BarrierSet::G1SATBCTLogging, "wrong barrier"); | 4599 bs->kind() == BarrierSet::G1SATBCTLogging, "wrong barrier"); |
4622 if (G1RSBarrierRegionFilter) { | 4600 if (G1RSBarrierRegionFilter) { |
4624 #ifdef _LP64 | 4602 #ifdef _LP64 |
4625 srlx(tmp, HeapRegion::LogOfHRGrainBytes, tmp); | 4603 srlx(tmp, HeapRegion::LogOfHRGrainBytes, tmp); |
4626 #else | 4604 #else |
4627 srl(tmp, HeapRegion::LogOfHRGrainBytes, tmp); | 4605 srl(tmp, HeapRegion::LogOfHRGrainBytes, tmp); |
4628 #endif | 4606 #endif |
4607 | |
4629 if (G1PrintCTFilterStats) { | 4608 if (G1PrintCTFilterStats) { |
4630 guarantee(tmp->is_global(), "Or stats won't work..."); | 4609 guarantee(tmp->is_global(), "Or stats won't work..."); |
4631 // This is a sleazy hack: I'm temporarily hijacking G2, which I | 4610 // This is a sleazy hack: I'm temporarily hijacking G2, which I |
4632 // promise to restore. | 4611 // promise to restore. |
4633 mov(new_val, G2); | 4612 mov(new_val, G2); |