213 bool ZBarrierSetC2::array_copy_requires_gc_barriers(bool tightly_coupled_alloc, BasicType type, |
214 bool ZBarrierSetC2::array_copy_requires_gc_barriers(bool tightly_coupled_alloc, BasicType type, |
214 bool is_clone, ArrayCopyPhase phase) const { |
215 bool is_clone, ArrayCopyPhase phase) const { |
215 return type == T_OBJECT || type == T_ARRAY; |
216 return type == T_OBJECT || type == T_ARRAY; |
216 } |
217 } |
217 |
218 |
|
219 // This TypeFunc assumes a 64bit system |
218 static const TypeFunc* clone_type() { |
220 static const TypeFunc* clone_type() { |
219 // Create input type (domain) |
221 // Create input type (domain) |
220 const Type** domain_fields = TypeTuple::fields(3); |
222 const Type** domain_fields = TypeTuple::fields(4); |
221 domain_fields[TypeFunc::Parms + 0] = TypeInstPtr::NOTNULL; // src |
223 domain_fields[TypeFunc::Parms + 0] = TypeInstPtr::NOTNULL; // src |
222 domain_fields[TypeFunc::Parms + 1] = TypeInstPtr::NOTNULL; // dst |
224 domain_fields[TypeFunc::Parms + 1] = TypeInstPtr::NOTNULL; // dst |
223 domain_fields[TypeFunc::Parms + 2] = TypeInt::INT; // size |
225 domain_fields[TypeFunc::Parms + 2] = TypeLong::LONG; // size lower |
224 const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + 3, domain_fields); |
226 domain_fields[TypeFunc::Parms + 3] = Type::HALF; // size upper |
|
227 const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + 4, domain_fields); |
225 |
228 |
226 // Create result type (range) |
229 // Create result type (range) |
227 const Type** range_fields = TypeTuple::fields(0); |
230 const Type** range_fields = TypeTuple::fields(0); |
228 const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 0, range_fields); |
231 const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 0, range_fields); |
229 |
232 |
230 return TypeFunc::make(domain, range); |
233 return TypeFunc::make(domain, range); |
231 } |
234 } |
232 |
235 |
|
236 // Node n is pointing to the start of oop payload - return base pointer |
|
237 static Node* get_base_for_arracycopy_clone(PhaseMacroExpand* phase, Node* n) { |
|
238 // This would normally be handled by optimizations, but the type system |
|
239 // checks get confused when it thinks it already has a base pointer. |
|
240 const int base_offset = BarrierSetC2::arraycopy_payload_base_offset(false); |
|
241 |
|
242 if (n->is_AddP() && |
|
243 n->in(AddPNode::Offset)->is_Con() && |
|
244 n->in(AddPNode::Offset)->get_long() == base_offset) { |
|
245 assert(n->in(AddPNode::Base) == n->in(AddPNode::Address), "Sanity check"); |
|
246 return n->in(AddPNode::Base); |
|
247 } else { |
|
248 return phase->basic_plus_adr(n, phase->longcon(-base_offset)); |
|
249 } |
|
250 } |
|
251 |
233 void ZBarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* ac) const { |
252 void ZBarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* ac) const { |
234 Node* const src = ac->in(ArrayCopyNode::Src); |
253 Node* const src = ac->in(ArrayCopyNode::Src); |
235 |
254 if (ac->is_clone_array()) { |
236 if (src->bottom_type()->isa_aryptr()) { |
|
237 // Clone primitive array |
255 // Clone primitive array |
238 BarrierSetC2::clone_at_expansion(phase, ac); |
256 BarrierSetC2::clone_at_expansion(phase, ac); |
239 return; |
257 return; |
240 } |
258 } |
241 |
259 |
242 // Clone instance |
260 // Clone instance |
243 Node* const ctrl = ac->in(TypeFunc::Control); |
261 assert(ac->is_clone_inst(), "Sanity check"); |
244 Node* const mem = ac->in(TypeFunc::Memory); |
262 |
245 Node* const dst = ac->in(ArrayCopyNode::Dest); |
263 Node* const ctrl = ac->in(TypeFunc::Control); |
|
264 Node* const mem = ac->in(TypeFunc::Memory); |
|
265 Node* const dst = ac->in(ArrayCopyNode::Dest); |
246 Node* const src_offset = ac->in(ArrayCopyNode::SrcPos); |
266 Node* const src_offset = ac->in(ArrayCopyNode::SrcPos); |
247 Node* const dst_offset = ac->in(ArrayCopyNode::DestPos); |
267 Node* const dst_offset = ac->in(ArrayCopyNode::DestPos); |
248 Node* const size = ac->in(ArrayCopyNode::Length); |
268 Node* const size = ac->in(ArrayCopyNode::Length); |
249 |
269 |
250 assert(src->bottom_type()->isa_instptr(), "Should be an instance"); |
|
251 assert(dst->bottom_type()->isa_instptr(), "Should be an instance"); |
|
252 assert(src_offset == NULL, "Should be null"); |
270 assert(src_offset == NULL, "Should be null"); |
253 assert(dst_offset == NULL, "Should be null"); |
271 assert(dst_offset == NULL, "Should be null"); |
|
272 assert(size->bottom_type()->is_long(), "Should be long"); |
|
273 |
|
274 // The src and dst point to the object payload rather than the object base |
|
275 Node* const src_base = get_base_for_arracycopy_clone(phase, src); |
|
276 Node* const dst_base = get_base_for_arracycopy_clone(phase, dst); |
|
277 |
|
278 // The size must also be increased to match the instance size |
|
279 Node* const base_offset = phase->longcon(arraycopy_payload_base_offset(false) >> LogBytesPerLong); |
|
280 Node* const full_size = phase->transform_later(new AddLNode(size, base_offset)); |
254 |
281 |
255 Node* const call = phase->make_leaf_call(ctrl, |
282 Node* const call = phase->make_leaf_call(ctrl, |
256 mem, |
283 mem, |
257 clone_type(), |
284 clone_type(), |
258 ZBarrierSetRuntime::clone_addr(), |
285 ZBarrierSetRuntime::clone_addr(), |
259 "ZBarrierSetRuntime::clone", |
286 "ZBarrierSetRuntime::clone", |
260 TypeRawPtr::BOTTOM, |
287 TypeRawPtr::BOTTOM, |
261 src, |
288 src_base, |
262 dst, |
289 dst_base, |
263 size); |
290 full_size, |
|
291 phase->top()); |
264 phase->transform_later(call); |
292 phase->transform_later(call); |
265 phase->igvn().replace_node(ac, call); |
293 phase->igvn().replace_node(ac, call); |
266 } |
294 } |
267 |
295 |
268 // == Dominating barrier elision == |
296 // == Dominating barrier elision == |