src/cpu/x86/vm/c1_LIRAssembler_x86.cpp

changeset 2728
13bc79b5c9c8
parent 2697
09f96c3ff1ad
child 2761
15c9a0e16269
     1.1 --- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp	Sat Apr 02 10:54:15 2011 -0700
     1.2 +++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp	Sun Apr 03 12:00:54 2011 +0200
     1.3 @@ -3102,7 +3102,7 @@
     1.4    BasicType basic_type = default_type != NULL ? default_type->element_type()->basic_type() : T_ILLEGAL;
     1.5    if (basic_type == T_ARRAY) basic_type = T_OBJECT;
     1.6  
     1.7 -  // if we don't know anything or it's an object array, just go through the generic arraycopy
     1.8 +  // if we don't know anything, just go through the generic arraycopy
     1.9    if (default_type == NULL) {
    1.10      Label done;
    1.11      // save outgoing arguments on stack in case call to System.arraycopy is needed
    1.12 @@ -3123,7 +3123,9 @@
    1.13      store_parameter(src, 4);
    1.14      NOT_LP64(assert(src == rcx && src_pos == rdx, "mismatch in calling convention");)
    1.15  
    1.16 -    address entry = CAST_FROM_FN_PTR(address, Runtime1::arraycopy);
    1.17 +    address C_entry = CAST_FROM_FN_PTR(address, Runtime1::arraycopy);
    1.18 +
    1.19 +    address copyfunc_addr = StubRoutines::generic_arraycopy();
    1.20  
    1.21      // pass arguments: may push as this is not a safepoint; SP must be fix at each safepoint
    1.22  #ifdef _LP64
    1.23 @@ -3141,11 +3143,29 @@
    1.24      // Allocate abi space for args but be sure to keep stack aligned
    1.25      __ subptr(rsp, 6*wordSize);
    1.26      store_parameter(j_rarg4, 4);
    1.27 -    __ call(RuntimeAddress(entry));
    1.28 +    if (copyfunc_addr == NULL) { // Use C version if stub was not generated
    1.29 +      __ call(RuntimeAddress(C_entry));
    1.30 +    } else {
    1.31 +#ifndef PRODUCT
    1.32 +      if (PrintC1Statistics) {
    1.33 +        __ incrementl(ExternalAddress((address)&Runtime1::_generic_arraycopystub_cnt));
    1.34 +      }
    1.35 +#endif
    1.36 +      __ call(RuntimeAddress(copyfunc_addr));
    1.37 +    }
    1.38      __ addptr(rsp, 6*wordSize);
    1.39  #else
    1.40      __ mov(c_rarg4, j_rarg4);
    1.41 -    __ call(RuntimeAddress(entry));
    1.42 +    if (copyfunc_addr == NULL) { // Use C version if stub was not generated
    1.43 +      __ call(RuntimeAddress(C_entry));
    1.44 +    } else {
    1.45 +#ifndef PRODUCT
    1.46 +      if (PrintC1Statistics) {
    1.47 +        __ incrementl(ExternalAddress((address)&Runtime1::_generic_arraycopystub_cnt));
    1.48 +      }
    1.49 +#endif
    1.50 +      __ call(RuntimeAddress(copyfunc_addr));
    1.51 +    }
    1.52  #endif // _WIN64
    1.53  #else
    1.54      __ push(length);
    1.55 @@ -3153,13 +3173,28 @@
    1.56      __ push(dst);
    1.57      __ push(src_pos);
    1.58      __ push(src);
    1.59 -    __ call_VM_leaf(entry, 5); // removes pushed parameter from the stack
    1.60 +
    1.61 +    if (copyfunc_addr == NULL) { // Use C version if stub was not generated
    1.62 +      __ call_VM_leaf(C_entry, 5); // removes pushed parameter from the stack
    1.63 +    } else {
    1.64 +#ifndef PRODUCT
    1.65 +      if (PrintC1Statistics) {
    1.66 +        __ incrementl(ExternalAddress((address)&Runtime1::_generic_arraycopystub_cnt));
    1.67 +      }
    1.68 +#endif
    1.69 +      __ call_VM_leaf(copyfunc_addr, 5); // removes pushed parameter from the stack
    1.70 +    }
    1.71  
    1.72  #endif // _LP64
    1.73  
    1.74      __ cmpl(rax, 0);
    1.75      __ jcc(Assembler::equal, *stub->continuation());
    1.76  
    1.77 +    if (copyfunc_addr != NULL) {
    1.78 +      __ mov(tmp, rax);
    1.79 +      __ xorl(tmp, -1);
    1.80 +    }
    1.81 +
    1.82      // Reload values from the stack so they are where the stub
    1.83      // expects them.
    1.84      __ movptr   (dst,     Address(rsp, 0*BytesPerWord));
    1.85 @@ -3167,6 +3202,12 @@
    1.86      __ movptr   (length,  Address(rsp, 2*BytesPerWord));
    1.87      __ movptr   (src_pos, Address(rsp, 3*BytesPerWord));
    1.88      __ movptr   (src,     Address(rsp, 4*BytesPerWord));
    1.89 +
    1.90 +    if (copyfunc_addr != NULL) {
    1.91 +      __ subl(length, tmp);
    1.92 +      __ addl(src_pos, tmp);
    1.93 +      __ addl(dst_pos, tmp);
    1.94 +    }
    1.95      __ jmp(*stub->entry());
    1.96  
    1.97      __ bind(*stub->continuation());
    1.98 @@ -3226,10 +3267,6 @@
    1.99      __ testl(dst_pos, dst_pos);
   1.100      __ jcc(Assembler::less, *stub->entry());
   1.101    }
   1.102 -  if (flags & LIR_OpArrayCopy::length_positive_check) {
   1.103 -    __ testl(length, length);
   1.104 -    __ jcc(Assembler::less, *stub->entry());
   1.105 -  }
   1.106  
   1.107    if (flags & LIR_OpArrayCopy::src_range_check) {
   1.108      __ lea(tmp, Address(src_pos, length, Address::times_1, 0));
   1.109 @@ -3242,15 +3279,190 @@
   1.110      __ jcc(Assembler::above, *stub->entry());
   1.111    }
   1.112  
   1.113 +  if (flags & LIR_OpArrayCopy::length_positive_check) {
   1.114 +    __ testl(length, length);
   1.115 +    __ jcc(Assembler::less, *stub->entry());
   1.116 +    __ jcc(Assembler::zero, *stub->continuation());
   1.117 +  }
   1.118 +
   1.119 +#ifdef _LP64
   1.120 +  __ movl2ptr(src_pos, src_pos); //higher 32bits must be null
   1.121 +  __ movl2ptr(dst_pos, dst_pos); //higher 32bits must be null
   1.122 +#endif
   1.123 +
   1.124    if (flags & LIR_OpArrayCopy::type_check) {
   1.125 -    if (UseCompressedOops) {
   1.126 -      __ movl(tmp, src_klass_addr);
   1.127 -      __ cmpl(tmp, dst_klass_addr);
   1.128 +    // We don't know the array types are compatible
   1.129 +    if (basic_type != T_OBJECT) {
   1.130 +      // Simple test for basic type arrays
   1.131 +      if (UseCompressedOops) {
   1.132 +        __ movl(tmp, src_klass_addr);
   1.133 +        __ cmpl(tmp, dst_klass_addr);
   1.134 +      } else {
   1.135 +        __ movptr(tmp, src_klass_addr);
   1.136 +        __ cmpptr(tmp, dst_klass_addr);
   1.137 +      }
   1.138 +      __ jcc(Assembler::notEqual, *stub->entry());
   1.139      } else {
   1.140 -      __ movptr(tmp, src_klass_addr);
   1.141 -      __ cmpptr(tmp, dst_klass_addr);
   1.142 +      // For object arrays, if src is a sub class of dst then we can
   1.143 +      // safely do the copy.
   1.144 +      Label cont, slow;
   1.145 +
   1.146 +      __ push(src);
   1.147 +      __ push(dst);
   1.148 +
   1.149 +      __ load_klass(src, src);
   1.150 +      __ load_klass(dst, dst);
   1.151 +
   1.152 +      __ check_klass_subtype_fast_path(src, dst, tmp, &cont, &slow, NULL);
   1.153 +
   1.154 +      __ push(src);
   1.155 +      __ push(dst);
   1.156 +      __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id)));
   1.157 +      __ pop(dst);
   1.158 +      __ pop(src);
   1.159 +
   1.160 +      __ cmpl(src, 0);
   1.161 +      __ jcc(Assembler::notEqual, cont);
   1.162 +
   1.163 +      __ bind(slow);
   1.164 +      __ pop(dst);
   1.165 +      __ pop(src);
   1.166 +
   1.167 +      address copyfunc_addr = StubRoutines::checkcast_arraycopy();
   1.168 +      if (copyfunc_addr != NULL) { // use stub if available
   1.169 +        // src is not a sub class of dst so we have to do a
   1.170 +        // per-element check.
   1.171 +
   1.172 +        int mask = LIR_OpArrayCopy::src_objarray|LIR_OpArrayCopy::dst_objarray;
   1.173 +        if ((flags & mask) != mask) {
   1.174 +          // Check that at least both of them object arrays.
   1.175 +          assert(flags & mask, "one of the two should be known to be an object array");
   1.176 +
   1.177 +          if (!(flags & LIR_OpArrayCopy::src_objarray)) {
   1.178 +            __ load_klass(tmp, src);
   1.179 +          } else if (!(flags & LIR_OpArrayCopy::dst_objarray)) {
   1.180 +            __ load_klass(tmp, dst);
   1.181 +          }
   1.182 +          int lh_offset = klassOopDesc::header_size() * HeapWordSize +
   1.183 +            Klass::layout_helper_offset_in_bytes();
   1.184 +          Address klass_lh_addr(tmp, lh_offset);
   1.185 +          jint objArray_lh = Klass::array_layout_helper(T_OBJECT);
   1.186 +          __ cmpl(klass_lh_addr, objArray_lh);
   1.187 +          __ jcc(Assembler::notEqual, *stub->entry());
   1.188 +        }
   1.189 +
   1.190 +#ifndef _LP64
   1.191 +        // save caller save registers
   1.192 +        store_parameter(rax, 2);
   1.193 +        store_parameter(rcx, 1);
   1.194 +        store_parameter(rdx, 0);
   1.195 +
   1.196 +        __ movptr(tmp, dst_klass_addr);
   1.197 +        __ movptr(tmp, Address(tmp, objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc)));
   1.198 +        __ push(tmp);
   1.199 +        __ movl(tmp, Address(tmp, Klass::super_check_offset_offset_in_bytes() + sizeof(oopDesc)));
   1.200 +        __ push(tmp);
   1.201 +        __ push(length);
   1.202 +        __ lea(tmp, Address(dst, dst_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type)));
   1.203 +        __ push(tmp);
   1.204 +        __ lea(tmp, Address(src, src_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type)));
   1.205 +        __ push(tmp);
   1.206 +
   1.207 +        __ call_VM_leaf(copyfunc_addr, 5);
   1.208 +#else
   1.209 +        __ movl2ptr(length, length); //higher 32bits must be null
   1.210 +
   1.211 +        // save caller save registers: copy them to callee save registers
   1.212 +        __ mov(rbx, rdx);
   1.213 +        __ mov(r13, r8);
   1.214 +        __ mov(r14, r9);
   1.215 +#ifndef _WIN64
   1.216 +        store_parameter(rsi, 1);
   1.217 +        store_parameter(rcx, 0);
   1.218 +        // on WIN64 other incoming parameters are in rdi and rsi saved
   1.219 +        // across the call
   1.220 +#endif
   1.221 +
   1.222 +        __ lea(c_rarg0, Address(src, src_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type)));
   1.223 +        assert_different_registers(c_rarg0, dst, dst_pos, length);
   1.224 +        __ lea(c_rarg1, Address(dst, dst_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type)));
   1.225 +        assert_different_registers(c_rarg1, dst, length);
   1.226 +
   1.227 +        __ mov(c_rarg2, length);
   1.228 +        assert_different_registers(c_rarg2, dst);
   1.229 +
   1.230 +#ifdef _WIN64
   1.231 +        // Allocate abi space for args but be sure to keep stack aligned
   1.232 +        __ subptr(rsp, 6*wordSize);
   1.233 +        __ load_klass(c_rarg3, dst);
   1.234 +        __ movptr(c_rarg3, Address(c_rarg3, objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc)));
   1.235 +        store_parameter(c_rarg3, 4);
   1.236 +        __ movl(c_rarg3, Address(c_rarg3, Klass::super_check_offset_offset_in_bytes() + sizeof(oopDesc)));
   1.237 +        __ call(RuntimeAddress(copyfunc_addr));
   1.238 +        __ addptr(rsp, 6*wordSize);
   1.239 +#else
   1.240 +        __ load_klass(c_rarg4, dst);
   1.241 +        __ movptr(c_rarg4, Address(c_rarg4, objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc)));
   1.242 +        __ movl(c_rarg3, Address(c_rarg4, Klass::super_check_offset_offset_in_bytes() + sizeof(oopDesc)));
   1.243 +        __ call(RuntimeAddress(copyfunc_addr));
   1.244 +#endif
   1.245 +
   1.246 +#endif
   1.247 +
   1.248 +#ifndef PRODUCT
   1.249 +        if (PrintC1Statistics) {
   1.250 +          Label failed;
   1.251 +          __ testl(rax, rax);
   1.252 +          __ jcc(Assembler::notZero, failed);
   1.253 +          __ incrementl(ExternalAddress((address)&Runtime1::_arraycopy_checkcast_cnt));
   1.254 +          __ bind(failed);
   1.255 +        }
   1.256 +#endif
   1.257 +
   1.258 +        __ testl(rax, rax);
   1.259 +        __ jcc(Assembler::zero, *stub->continuation());
   1.260 +
   1.261 +#ifndef PRODUCT
   1.262 +        if (PrintC1Statistics) {
   1.263 +          __ incrementl(ExternalAddress((address)&Runtime1::_arraycopy_checkcast_attempt_cnt));
   1.264 +        }
   1.265 +#endif
   1.266 +
   1.267 +        __ mov(tmp, rax);
   1.268 +
   1.269 +        __ xorl(tmp, -1);
   1.270 +
   1.271 +#ifndef _LP64
   1.272 +        // restore caller save registers
   1.273 +        assert_different_registers(tmp, rdx, rcx, rax); // result of stub will be lost
   1.274 +        __ movptr(rdx, Address(rsp, 0*BytesPerWord));
   1.275 +        __ movptr(rcx, Address(rsp, 1*BytesPerWord));
   1.276 +        __ movptr(rax, Address(rsp, 2*BytesPerWord));
   1.277 +#else
   1.278 +        // restore caller save registers
   1.279 +        __ mov(rdx, rbx);
   1.280 +        __ mov(r8, r13);
   1.281 +        __ mov(r9, r14);
   1.282 +#ifndef _WIN64
   1.283 +        assert_different_registers(tmp, rdx, r8, r9, rcx, rsi); // result of stub will be lost
   1.284 +        __ movptr(rcx, Address(rsp, 0*BytesPerWord));
   1.285 +        __ movptr(rsi, Address(rsp, 1*BytesPerWord));
   1.286 +#else
   1.287 +        assert_different_registers(tmp, rdx, r8, r9); // result of stub will be lost
   1.288 +#endif
   1.289 +#endif
   1.290 +
   1.291 +        __ subl(length, tmp);
   1.292 +        __ addl(src_pos, tmp);
   1.293 +        __ addl(dst_pos, tmp);
   1.294 +      }
   1.295 +
   1.296 +      __ jmp(*stub->entry());
   1.297 +
   1.298 +      __ bind(cont);
   1.299 +      __ pop(dst);
   1.300 +      __ pop(src);
   1.301      }
   1.302 -    __ jcc(Assembler::notEqual, *stub->entry());
   1.303    }
   1.304  
   1.305  #ifdef ASSERT
   1.306 @@ -3291,16 +3503,16 @@
   1.307    }
   1.308  #endif
   1.309  
   1.310 -  if (shift_amount > 0 && basic_type != T_OBJECT) {
   1.311 -    __ shlptr(length, shift_amount);
   1.312 +#ifndef PRODUCT
   1.313 +  if (PrintC1Statistics) {
   1.314 +    __ incrementl(ExternalAddress(Runtime1::arraycopy_count_address(basic_type)));
   1.315    }
   1.316 +#endif
   1.317  
   1.318  #ifdef _LP64
   1.319    assert_different_registers(c_rarg0, dst, dst_pos, length);
   1.320 -  __ movl2ptr(src_pos, src_pos); //higher 32bits must be null
   1.321    __ lea(c_rarg0, Address(src, src_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type)));
   1.322    assert_different_registers(c_rarg1, length);
   1.323 -  __ movl2ptr(dst_pos, dst_pos); //higher 32bits must be null
   1.324    __ lea(c_rarg1, Address(dst, dst_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type)));
   1.325    __ mov(c_rarg2, length);
   1.326  
   1.327 @@ -3311,11 +3523,12 @@
   1.328    store_parameter(tmp, 1);
   1.329    store_parameter(length, 2);
   1.330  #endif // _LP64
   1.331 -  if (basic_type == T_OBJECT) {
   1.332 -    __ call_VM_leaf(CAST_FROM_FN_PTR(address, Runtime1::oop_arraycopy), 0);
   1.333 -  } else {
   1.334 -    __ call_VM_leaf(CAST_FROM_FN_PTR(address, Runtime1::primitive_arraycopy), 0);
   1.335 -  }
   1.336 +
   1.337 +  bool disjoint = (flags & LIR_OpArrayCopy::overlapping) == 0;
   1.338 +  bool aligned = (flags & LIR_OpArrayCopy::unaligned) == 0;
   1.339 +  const char *name;
   1.340 +  address entry = StubRoutines::select_arraycopy_function(basic_type, aligned, disjoint, name, false);
   1.341 +  __ call_VM_leaf(entry, 0);
   1.342  
   1.343    __ bind(*stub->continuation());
   1.344  }

mercurial