< prev index next >
src/share/vm/opto/library_call.cpp
Print this page
@@ -26,10 +26,11 @@
#include "asm/macroAssembler.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/compileLog.hpp"
+#include "gc/shenandoah/shenandoahRuntime.hpp"
#include "oops/objArrayKlass.hpp"
#include "opto/addnode.hpp"
#include "opto/arraycopynode.hpp"
#include "opto/c2compiler.hpp"
#include "opto/callGenerator.hpp"
@@ -44,10 +45,11 @@
#include "opto/mulnode.hpp"
#include "opto/narrowptrnode.hpp"
#include "opto/opaquenode.hpp"
#include "opto/parse.hpp"
#include "opto/runtime.hpp"
+#include "opto/shenandoahSupport.hpp"
#include "opto/subnode.hpp"
#include "prims/nativeLookup.hpp"
#include "runtime/sharedRuntime.hpp"
#include "trace/traceMacros.hpp"
@@ -970,13 +972,23 @@
}
//------------------------------inline_string_equals------------------------
bool LibraryCallKit::inline_string_equals() {
Node* receiver = null_check_receiver();
+
+ if (ShenandoahVerifyReadsToFromSpace) {
+ receiver = shenandoah_read_barrier(receiver);
+ }
+
// NOTE: Do not null check argument for String.equals() because spec
// allows to specify NULL as argument.
Node* argument = this->argument(1);
+
+ if (ShenandoahVerifyReadsToFromSpace) {
+ argument = shenandoah_read_barrier(argument);
+ }
+
if (stopped()) {
return true;
}
// paths (plus control) merge
@@ -1021,18 +1033,28 @@
Node* no_ctrl = NULL;
// Get start addr of receiver
Node* receiver_val = load_String_value(no_ctrl, receiver);
+
+ if (ShenandoahVerifyReadsToFromSpace) {
+ receiver_val = shenandoah_read_barrier(receiver_val);
+ }
+
Node* receiver_offset = load_String_offset(no_ctrl, receiver);
Node* receiver_start = array_element_address(receiver_val, receiver_offset, T_CHAR);
// Get length of receiver
Node* receiver_cnt = load_String_length(no_ctrl, receiver);
// Get start addr of argument
Node* argument_val = load_String_value(no_ctrl, argument);
+
+ if (ShenandoahVerifyReadsToFromSpace) {
+ argument_val = shenandoah_read_barrier(argument_val);
+ }
+
Node* argument_offset = load_String_offset(no_ctrl, argument);
Node* argument_start = array_element_address(argument_val, argument_offset, T_CHAR);
// Get length of argument
Node* argument_cnt = load_String_length(no_ctrl, argument);
@@ -1065,10 +1087,14 @@
//------------------------------inline_array_equals----------------------------
bool LibraryCallKit::inline_array_equals() {
Node* arg1 = argument(0);
Node* arg2 = argument(1);
+
+ arg1 = shenandoah_read_barrier(arg1);
+ arg2 = shenandoah_read_barrier(arg2);
+
set_result(_gvn.transform(new AryEqNode(control(), memory(TypeAryPtr::CHARS), arg1, arg2)));
return true;
}
// Java version of String.indexOf(constant string)
@@ -2150,11 +2176,11 @@
// is enabled, we need to log the value in the referent field in an SATB buffer.
// This routine performs some compile time filters and generates suitable
// runtime filters that guard the pre-barrier code.
// Also add memory barrier for non volatile load from the referent field
// to prevent commoning of loads across safepoint.
- if (!UseG1GC && !need_mem_bar)
+ if (!(UseG1GC || UseShenandoahGC) && !need_mem_bar)
return;
// Some compile time checks.
// If offset is a constant, is it java_lang_ref_Reference::_reference_offset?
@@ -2339,10 +2365,21 @@
Node* val;
if (!is_native_ptr) {
// The base is either a Java object or a value produced by Unsafe.staticFieldBase
Node* base = argument(1); // type: oop
+ if (UseShenandoahGC) {
+ // Note: if we don't null-check here, we generate a read barrier with a built-in
+ // null-check. This will later be attempted to be split on the phi, which
+ // results in a load on a NULL-based address on the null-path, which blowsup.
+ base = null_check(base);
+ }
+ if (is_store) {
+ base = shenandoah_write_barrier(base);
+ } else {
+ base = shenandoah_read_barrier(base);
+ }
// The offset is a value produced by Unsafe.staticFieldOffset or Unsafe.objectFieldOffset
offset = argument(2); // type: long
// We currently rely on the cookies produced by Unsafe.xxxFieldOffset
// to be plain byte offsets, which are also the same as those accepted
// by oopDesc::field_base.
@@ -2490,10 +2527,11 @@
MemNode::MemOrd mo = is_volatile ? MemNode::release : MemNode::unordered;
if (type != T_OBJECT ) {
(void) store_to_memory(control(), adr, val, type, adr_type, mo, is_volatile);
} else {
+ val = shenandoah_read_barrier_nomem(val);
// Possibly an oop being stored to Java heap or native memory
if (!TypePtr::NULL_PTR->higher_equal(_gvn.type(heap_base_oop))) {
// oop to Java heap.
(void) store_oop_to_unknown(control(), heap_base_oop, adr, adr_type, val, type, mo);
} else {
@@ -2619,10 +2657,12 @@
receiver = null_check(receiver);
if (stopped()) {
return true;
}
+ base = shenandoah_write_barrier(base);
+
// Build field offset expression.
// We currently rely on the cookies produced by Unsafe.xxxFieldOffset
// to be plain byte offsets, which are also the same as those accepted
// by oopDesc::field_base.
assert(Unsafe_field_offset_to_byte_offset(11) == 11, "fieldOffset must be byte-scaled");
@@ -2660,10 +2700,11 @@
Node *mem = memory(alias_idx);
// For now, we handle only those cases that actually exist: ints,
// longs, and Object. Adding others should be straightforward.
Node* load_store;
+ Node* result;
switch(type) {
case T_INT:
if (kind == LS_xadd) {
load_store = _gvn.transform(new GetAndAddINode(control(), mem, adr, newval, adr_type));
} else if (kind == LS_xchg) {
@@ -2671,10 +2712,11 @@
} else if (kind == LS_cmpxchg) {
load_store = _gvn.transform(new CompareAndSwapINode(control(), mem, adr, newval, oldval));
} else {
ShouldNotReachHere();
}
+ result = load_store;
break;
case T_LONG:
if (kind == LS_xadd) {
load_store = _gvn.transform(new GetAndAddLNode(control(), mem, adr, newval, adr_type));
} else if (kind == LS_xchg) {
@@ -2682,18 +2724,21 @@
} else if (kind == LS_cmpxchg) {
load_store = _gvn.transform(new CompareAndSwapLNode(control(), mem, adr, newval, oldval));
} else {
ShouldNotReachHere();
}
+ result = load_store;
break;
case T_OBJECT:
// Transformation of a value which could be NULL pointer (CastPP #NULL)
// could be delayed during Parse (for example, in adjust_map_after_if()).
// Execute transformation here to avoid barrier generation in such case.
if (_gvn.type(newval) == TypePtr::NULL_PTR)
newval = _gvn.makecon(TypePtr::NULL_PTR);
+ newval = shenandoah_read_barrier_nomem(newval);
+
// Reference stores need a store barrier.
if (kind == LS_xchg) {
// If pre-barrier must execute before the oop store, old value will require do_load here.
if (!can_move_pre_barrier()) {
pre_barrier(true /* do_load*/,
@@ -2725,35 +2770,98 @@
assert(kind == LS_cmpxchg, "wrong LoadStore operation");
Node *oldval_enc = _gvn.transform(new EncodePNode(oldval, oldval->bottom_type()->make_narrowoop()));
load_store = _gvn.transform(new CompareAndSwapNNode(control(), mem, adr,
newval_enc, oldval_enc));
}
+ result = load_store;
} else
#endif
{
if (kind == LS_xchg) {
load_store = _gvn.transform(new GetAndSetPNode(control(), mem, adr, newval, adr_type, value_type->is_oopptr()));
+ result = load_store;
} else {
assert(kind == LS_cmpxchg, "wrong LoadStore operation");
load_store = _gvn.transform(new CompareAndSwapPNode(control(), mem, adr, newval, oldval));
+ result = load_store;
+
+ if (UseShenandoahGC) {
+ // if (! success)
+ Node* cmp_true = _gvn.transform(new CmpINode(load_store, intcon(1)));
+ Node* tst_true = _gvn.transform(new BoolNode(cmp_true, BoolTest::eq));
+ IfNode* iff = create_and_map_if(control(), tst_true, PROB_LIKELY_MAG(2), COUNT_UNKNOWN);
+ Node* iftrue = _gvn.transform(new IfTrueNode(iff));
+ Node* iffalse = _gvn.transform(new IfFalseNode(iff));
+
+ enum { _success_path = 1, _fail_path, _shenandoah_path, PATH_LIMIT };
+ RegionNode* region = new RegionNode(PATH_LIMIT);
+ Node* phi = new PhiNode(region, TypeInt::BOOL);
+ // success -> return result of CAS1.
+ region->init_req(_success_path, iftrue);
+ phi ->init_req(_success_path, load_store);
+
+ // failure
+ set_control(iffalse);
+
+ // if (read_barrier(expected) == read_barrier(old)
+ oldval = shenandoah_read_barrier(oldval);
+
+ // Load old value from memory. We should really use what we get back from the CAS,
+ // if we can.
+ Node* current = make_load(control(), adr, TypeInstPtr::BOTTOM, type, MemNode::unordered);
+ // read_barrier(old)
+ Node* new_current = shenandoah_read_barrier(current);
+
+ Node* chk = _gvn.transform(new CmpPNode(new_current, oldval));
+ Node* test = _gvn.transform(new BoolNode(chk, BoolTest::eq));
+
+ IfNode* iff2 = create_and_map_if(control(), test, PROB_UNLIKELY_MAG(2), COUNT_UNKNOWN);
+ Node* iftrue2 = _gvn.transform(new IfTrueNode(iff2));
+ Node* iffalse2 = _gvn.transform(new IfFalseNode(iff2));
+
+ // If they are not equal, it's a legitimate failure and we return the result of CAS1.
+ region->init_req(_fail_path, iffalse2);
+ phi ->init_req(_fail_path, load_store);
+
+ // Otherwise we retry with old.
+ set_control(iftrue2);
+
+ Node *call = make_runtime_call(RC_LEAF | RC_NO_IO,
+ OptoRuntime::shenandoah_cas_obj_Type(),
+ CAST_FROM_FN_PTR(address, ShenandoahRuntime::compare_and_swap_object),
+ "shenandoah_cas_obj",
+ NULL,
+ adr, newval, current);
+
+ Node* retval = _gvn.transform(new ProjNode(call, TypeFunc::Parms + 0));
+
+ region->init_req(_shenandoah_path, control());
+ phi ->init_req(_shenandoah_path, retval);
+
+ set_control(_gvn.transform(region));
+ record_for_igvn(region);
+ phi = _gvn.transform(phi);
+ result = phi;
+ }
+
}
}
if (kind == LS_cmpxchg) {
// Emit the post barrier only when the actual store happened.
// This makes sense to check only for compareAndSet that can fail to set the value.
// CAS success path is marked more likely since we anticipate this is a performance
// critical path, while CAS failure path can use the penalty for going through unlikely
// path as backoff. Which is still better than doing a store barrier there.
IdealKit ideal(this);
- ideal.if_then(load_store, BoolTest::ne, ideal.ConI(0), PROB_STATIC_FREQUENT); {
+ ideal.if_then(result, BoolTest::ne, ideal.ConI(0), PROB_STATIC_FREQUENT); {
sync_kit(ideal);
- post_barrier(ideal.ctrl(), load_store, base, adr, alias_idx, newval, T_OBJECT, true);
+ post_barrier(ideal.ctrl(), result, base, adr, alias_idx, newval, T_OBJECT, true);
ideal.sync_kit(this);
} ideal.end_if();
final_sync(ideal);
} else {
- post_barrier(control(), load_store, base, adr, alias_idx, newval, T_OBJECT, true);
+ post_barrier(control(), result, base, adr, alias_idx, newval, T_OBJECT, true);
}
break;
default:
fatal(err_msg_res("unexpected type %d: %s", type, type2name(type)));
break;
@@ -2766,30 +2874,30 @@
set_memory(proj, alias_idx);
if (type == T_OBJECT && kind == LS_xchg) {
#ifdef _LP64
if (adr->bottom_type()->is_ptr_to_narrowoop()) {
- load_store = _gvn.transform(new DecodeNNode(load_store, load_store->get_ptr_type()));
+ result = _gvn.transform(new DecodeNNode(result, result->get_ptr_type()));
}
#endif
if (can_move_pre_barrier()) {
// Don't need to load pre_val. The old value is returned by load_store.
// The pre_barrier can execute after the xchg as long as no safepoint
// gets inserted between them.
pre_barrier(false /* do_load */,
control(), NULL, NULL, max_juint, NULL, NULL,
- load_store /* pre_val */,
+ result /* pre_val */,
T_OBJECT);
}
}
// Add the trailing membar surrounding the access
insert_mem_bar(Op_MemBarCPUOrder);
insert_mem_bar(Op_MemBarAcquire);
- assert(type2size[load_store->bottom_type()->basic_type()] == type2size[rtype], "result type should match");
- set_result(load_store);
+ assert(type2size[result->bottom_type()->basic_type()] == type2size[rtype], "result type should match");
+ set_result(result);
return true;
}
//----------------------------inline_unsafe_ordered_store----------------------
// public native void sun.misc.Unsafe.putOrderedObject(Object o, long offset, Object x);
@@ -2829,10 +2937,12 @@
receiver = null_check(receiver);
if (stopped()) {
return true;
}
+ base = shenandoah_write_barrier(base);
+
// Build field offset expression.
assert(Unsafe_field_offset_to_byte_offset(11) == 11, "fieldOffset must be byte-scaled");
// 32-bit machines ignore the high half of long offsets
offset = ConvL2X(offset);
Node* adr = make_unsafe_address(base, offset);
@@ -2843,12 +2953,14 @@
insert_mem_bar(Op_MemBarRelease);
insert_mem_bar(Op_MemBarCPUOrder);
// Ensure that the store is atomic for longs:
const bool require_atomic_access = true;
Node* store;
- if (type == T_OBJECT) // reference stores need a store barrier.
+ if (type == T_OBJECT) { // reference stores need a store barrier.
+ val = shenandoah_read_barrier_nomem(val);
store = store_oop_to_unknown(control(), base, adr, adr_type, val, type, MemNode::release);
+ }
else {
store = store_to_memory(control(), adr, val, type, adr_type, MemNode::release, require_atomic_access);
}
insert_mem_bar(Op_MemBarCPUOrder);
return true;
@@ -3166,17 +3278,25 @@
bool expect_prim = false; // most of these guys expect to work on refs
enum { _normal_path = 1, _prim_path = 2, PATH_LIMIT };
Node* mirror = argument(0);
+
+ if (ShenandoahVerifyReadsToFromSpace) {
+ mirror = shenandoah_read_barrier(mirror);
+ }
+
Node* obj = top();
switch (id) {
case vmIntrinsics::_isInstance:
// nothing is an instance of a primitive type
prim_return_value = intcon(0);
obj = argument(1);
+ if (ShenandoahVerifyReadsToFromSpace) {
+ obj = shenandoah_read_barrier(obj);
+ }
break;
case vmIntrinsics::_getModifiers:
prim_return_value = intcon(JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC);
assert(is_power_of_2((int)JVM_ACC_WRITTEN_FLAGS+1), "change next line");
return_type = TypeInt::make(0, JVM_ACC_WRITTEN_FLAGS, Type::WidenMin);
@@ -3482,10 +3602,11 @@
// we must return true when they are identical primitives.
// It is convenient to test this after the first null klass check.
set_control(region->in(_prim_0_path)); // go back to first null check
if (!stopped()) {
// Since superc is primitive, make a guard for the superc==subc case.
+ shenandoah_acmp_barrier(args[0], args[1]);
Node* cmp_eq = _gvn.transform(new CmpPNode(args[0], args[1]));
Node* bol_eq = _gvn.transform(new BoolNode(cmp_eq, BoolTest::eq));
generate_guard(bol_eq, region, PROB_FAIR);
if (region->req() == PATH_LIMIT+1) {
// A guard was added. If the added guard is taken, superc==subc.
@@ -3726,10 +3847,12 @@
// How many elements will we copy from the original?
// The answer is MinI(orig_length - start, length).
Node* orig_tail = _gvn.transform(new SubINode(orig_length, start));
Node* moved = generate_min_max(vmIntrinsics::_min, orig_tail, length);
+ original = shenandoah_read_barrier(original);
+
// Generate a direct call to the right arraycopy function(s).
// We know the copy is disjoint but we might not know if the
// oop stores need checking.
// Extreme case: Arrays.copyOf((Integer[])x, 10, String[].class).
// This will fail a store-check if x contains any non-nulls.
@@ -3907,10 +4030,14 @@
obj = null_check_oop(obj, &null_ctl);
result_reg->init_req(_null_path, null_ctl);
result_val->init_req(_null_path, _gvn.intcon(0));
}
+ if (ShenandoahVerifyReadsToFromSpace) {
+ obj = shenandoah_read_barrier(obj);
+ }
+
// Unconditionally null? Then return right away.
if (stopped()) {
set_control( result_reg->in(_null_path));
if (!stopped())
set_result(result_val->in(_null_path));
@@ -4222,10 +4349,13 @@
Node* size = ConvL2X(argument(7)); // type: long
assert(Unsafe_field_offset_to_byte_offset(11) == 11,
"fieldOffset must be byte-scaled");
+ src_ptr = shenandoah_read_barrier(src_ptr);
+ dst_ptr = shenandoah_write_barrier(dst_ptr);
+
Node* src = make_unsafe_address(src_ptr, src_off);
Node* dst = make_unsafe_address(dst_ptr, dst_off);
// Conservatively insert a memory barrier on all memory slices.
// Do not let writes of the copy source or destination float below the copy.
@@ -4250,10 +4380,12 @@
void LibraryCallKit::copy_to_clone(Node* obj, Node* alloc_obj, Node* obj_size, bool is_array, bool card_mark) {
assert(obj_size != NULL, "");
Node* raw_obj = alloc_obj->in(1);
assert(alloc_obj->is_CheckCastPP() && raw_obj->is_Proj() && raw_obj->in(0)->is_Allocate(), "");
+ obj = shenandoah_read_barrier(obj);
+
AllocateNode* alloc = NULL;
if (ReduceBulkZeroing) {
// We will be completely responsible for initializing this object -
// mark Initialize node as complete.
alloc = AllocateNode::Ideal_allocation(alloc_obj, &_gvn);
@@ -4307,10 +4439,19 @@
set_predefined_output_for_runtime_call(ac, ac->in(TypeFunc::Memory), raw_adr_type);
} else {
set_all_memory(n);
}
+ if (UseShenandoahGC) {
+ // Make sure that references in the cloned object are updated for Shenandoah.
+ make_runtime_call(RC_LEAF|RC_NO_FP,
+ OptoRuntime::shenandoah_clone_barrier_Type(),
+ CAST_FROM_FN_PTR(address, SharedRuntime::shenandoah_clone_barrier),
+ "shenandoah_clone_barrier", TypePtr::BOTTOM,
+ alloc_obj);
+ }
+
// If necessary, emit some card marks afterwards. (Non-arrays only.)
if (card_mark) {
assert(!is_array, "");
// Put in store barrier for any and all oops we are sticking
// into this object. (We could avoid this if we could prove
@@ -4433,10 +4574,13 @@
// because card marking is required on each card of the array.
Node* is_obja = generate_objArray_guard(obj_klass, (RegionNode*)NULL);
if (is_obja != NULL) {
PreserveJVMState pjvms2(this);
set_control(is_obja);
+
+ obj = shenandoah_read_barrier(obj);
+
// Generate a direct call to the right arraycopy function(s).
Node* alloc = tightly_coupled_allocation(alloc_obj, NULL);
ArrayCopyNode* ac = ArrayCopyNode::make(this, true, obj, intcon(0), alloc_obj, intcon(0), obj_length, alloc != NULL);
ac->set_cloneoop();
Node* n = _gvn.transform(ac);
@@ -4891,10 +5035,13 @@
if (stopped()) {
return true;
}
+ src = shenandoah_read_barrier(src);
+ dest = shenandoah_write_barrier(dest);
+
ArrayCopyNode* ac = ArrayCopyNode::make(this, true, src, src_offset, dest, dest_offset, length, alloc != NULL,
// Create LoadRange and LoadKlass nodes for use during macro expansion here
// so the compiler has a chance to eliminate them: during macro expansion,
// we have to set their control (CastPP nodes are eliminated).
load_object_klass(src), load_object_klass(dest),
@@ -4920,10 +5067,12 @@
LibraryCallKit::tightly_coupled_allocation(Node* ptr,
RegionNode* slow_region) {
if (stopped()) return NULL; // no fast path
if (C->AliasLevel() == 0) return NULL; // no MergeMems around
+ ptr = ShenandoahBarrierNode::skip_through_barrier(ptr);
+
AllocateArrayNode* alloc = AllocateArrayNode::Ideal_array_allocation(ptr, &_gvn);
if (alloc == NULL) return NULL;
Node* rawmem = memory(Compile::AliasIdxRaw);
// Is the allocation's memory state untouched?
@@ -4999,10 +5148,13 @@
Node *src_offset = argument(1);
Node *dst = argument(2);
Node *dst_offset = argument(3);
Node *length = argument(4);
+ src = shenandoah_read_barrier(src);
+ dst = shenandoah_write_barrier(dst);
+
const Type* src_type = src->Value(&_gvn);
const Type* dst_type = dst->Value(&_gvn);
const TypeAryPtr* top_src = src_type->isa_aryptr();
const TypeAryPtr* top_dest = dst_type->isa_aryptr();
if (top_src == NULL || top_src->klass() == NULL ||
@@ -5048,10 +5200,14 @@
Node* xlen = argument(1);
Node* y = argument(2);
Node* ylen = argument(3);
Node* z = argument(4);
+ x = shenandoah_read_barrier(x);
+ y = shenandoah_read_barrier(y);
+ z = shenandoah_write_barrier(z);
+
const Type* x_type = x->Value(&_gvn);
const Type* y_type = y->Value(&_gvn);
const TypeAryPtr* top_x = x_type->isa_aryptr();
const TypeAryPtr* top_y = y_type->isa_aryptr();
if (top_x == NULL || top_x->klass() == NULL ||
@@ -5148,10 +5304,13 @@
Node* x = argument(0);
Node* len = argument(1);
Node* z = argument(2);
Node* zlen = argument(3);
+ x = shenandoah_read_barrier(x);
+ z = shenandoah_write_barrier(z);
+
const Type* x_type = x->Value(&_gvn);
const Type* z_type = z->Value(&_gvn);
const TypeAryPtr* top_x = x_type->isa_aryptr();
const TypeAryPtr* top_z = z_type->isa_aryptr();
if (top_x == NULL || top_x->klass() == NULL ||
@@ -5195,10 +5354,13 @@
Node* in = argument(1);
Node* offset = argument(2);
Node* len = argument(3);
Node* k = argument(4);
+ in = shenandoah_read_barrier(in);
+ out = shenandoah_write_barrier(out);
+
const Type* out_type = out->Value(&_gvn);
const Type* in_type = in->Value(&_gvn);
const TypeAryPtr* top_out = out_type->isa_aryptr();
const TypeAryPtr* top_in = in_type->isa_aryptr();
if (top_out == NULL || top_out->klass() == NULL ||
@@ -5244,10 +5406,15 @@
Node* n = argument(2);
Node* len = argument(3);
Node* inv = argument(4);
Node* m = argument(6);
+ a = shenandoah_read_barrier(a);
+ b = shenandoah_read_barrier(b);
+ n = shenandoah_read_barrier(n);
+ m = shenandoah_write_barrier(m);
+
const Type* a_type = a->Value(&_gvn);
const TypeAryPtr* top_a = a_type->isa_aryptr();
const Type* b_type = b->Value(&_gvn);
const TypeAryPtr* top_b = b_type->isa_aryptr();
const Type* n_type = a->Value(&_gvn);
@@ -5303,10 +5470,14 @@
Node* n = argument(1);
Node* len = argument(2);
Node* inv = argument(3);
Node* m = argument(5);
+ a = shenandoah_read_barrier(a);
+ n = shenandoah_read_barrier(n);
+ m = shenandoah_write_barrier(m);
+
const Type* a_type = a->Value(&_gvn);
const TypeAryPtr* top_a = a_type->isa_aryptr();
const Type* n_type = a->Value(&_gvn);
const TypeAryPtr* top_n = n_type->isa_aryptr();
const Type* m_type = a->Value(&_gvn);
@@ -5403,10 +5574,11 @@
if (src_elem != T_BYTE) {
return false;
}
// 'src_start' points to src array + scaled offset
+ src = shenandoah_read_barrier(src);
Node* src_start = array_element_address(src, offset, src_elem);
// We assume that range check is done by caller.
// TODO: generate range check (offset+length < src.length) in debug VM.
@@ -5491,14 +5663,16 @@
if (src_elem != T_BYTE) {
return false;
}
// 'src_start' points to src array + scaled offset
+ src = shenandoah_read_barrier(src);
Node* src_start = array_element_address(src, offset, src_elem);
// static final int[] byteTable in class CRC32C
Node* table = get_table_from_crc32c_class(callee()->holder());
+ table = shenandoah_read_barrier(table);
Node* table_start = array_element_address(table, intcon(0), T_INT);
// We assume that range check is done by caller.
// TODO: generate range check (offset+length < src.length) in debug VM.
@@ -5538,10 +5712,11 @@
// 'src_start' points to src array + scaled offset
Node* src_start = basic_plus_adr(top(), base, offset);
// static final int[] byteTable in class CRC32C
Node* table = get_table_from_crc32c_class(callee()->holder());
+ table = shenandoah_read_barrier(table);
Node* table_start = array_element_address(table, intcon(0), T_INT);
// Call the stub.
address stubAddr = StubRoutines::updateBytesCRC32C();
const char *stubName = "updateBytesCRC32C";
@@ -5581,10 +5756,11 @@
if (src_elem != T_BYTE) {
return false;
}
// 'src_start' points to src array + scaled offset
+ src = shenandoah_read_barrier(src);
Node* src_start = array_element_address(src, offset, src_elem);
// We assume that range check is done by caller.
// TODO: generate range check (offset+length < src.length) in debug VM.
@@ -5643,10 +5819,14 @@
// Get the argument:
Node* reference_obj = null_check_receiver();
if (stopped()) return true;
+ if (ShenandoahVerifyReadsToFromSpace) {
+ reference_obj = shenandoah_read_barrier(reference_obj);
+ }
+
Node* adr = basic_plus_adr(reference_obj, reference_obj, referent_offset);
ciInstanceKlass* klass = env()->Object_klass();
const TypeOopPtr* object_type = TypeOopPtr::make_from_klass(klass);
@@ -5691,10 +5871,12 @@
if (is_static) {
const TypeInstPtr* tip = TypeInstPtr::make(fromKls->java_mirror());
fromObj = makecon(tip);
}
+ fromObj = shenandoah_read_barrier(fromObj);
+
// Next code copied from Parse::do_get_xxx():
// Compute address and memory type.
int offset = field->offset_in_bytes();
bool is_vol = field->is_volatile();
@@ -5751,10 +5933,14 @@
Node* src = argument(1);
Node* src_offset = argument(2);
Node* dest = argument(3);
Node* dest_offset = argument(4);
+ // Resolve src and dest arrays for ShenandoahGC.
+ src = shenandoah_read_barrier(src);
+ dest = shenandoah_write_barrier(dest);
+
// (1) src and dest are arrays.
const Type* src_type = src->Value(&_gvn);
const Type* dest_type = dest->Value(&_gvn);
const TypeAryPtr* top_src = src_type->isa_aryptr();
const TypeAryPtr* top_dest = dest_type->isa_aryptr();
@@ -5819,10 +6005,14 @@
Node* src_offset = argument(2);
Node* len = argument(3);
Node* dest = argument(4);
Node* dest_offset = argument(5);
+ // Resolve src and dest arrays for ShenandoahGC.
+ src = shenandoah_read_barrier(src);
+ dest = shenandoah_write_barrier(dest);
+
// (1) src and dest are arrays.
const Type* src_type = src->Value(&_gvn);
const Type* dest_type = dest->Value(&_gvn);
const TypeAryPtr* top_src = src_type->isa_aryptr();
const TypeAryPtr* top_dest = dest_type->isa_aryptr();
@@ -5863,10 +6053,13 @@
Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object);
if (k_start == NULL) return false;
// similarly, get the start address of the r vector
Node* objRvec = load_field_from_object(cipherBlockChaining_object, "r", "[B", /*is_exact*/ false);
+
+ objRvec = shenandoah_write_barrier(objRvec);
+
if (objRvec == NULL) return false;
Node* r_start = array_element_address(objRvec, intcon(0), T_BYTE);
Node* cbcCrypt;
if (Matcher::pass_original_key_for_aes()) {
@@ -5898,10 +6091,12 @@
Node * LibraryCallKit::get_key_start_from_aescrypt_object(Node *aescrypt_object) {
Node* objAESCryptKey = load_field_from_object(aescrypt_object, "K", "[I", /*is_exact*/ false);
assert (objAESCryptKey != NULL, "wrong version of com.sun.crypto.provider.AESCrypt");
if (objAESCryptKey == NULL) return (Node *) NULL;
+ objAESCryptKey = shenandoah_read_barrier(objAESCryptKey);
+
// now have the array, need to get the start address of the K array
Node* k_start = array_element_address(objAESCryptKey, intcon(0), T_INT);
return k_start;
}
< prev index next >