comparison src/cpu/x86/vm/assembler_x86.cpp @ 644:c517646eef23

6813212: factor duplicated assembly code for general subclass check (for 6655638) Summary: Code in interp_masm, stubGenerator, c1_LIRAssembler, and AD files moved into MacroAssembler. Reviewed-by: kvn
author jrose
date Fri, 13 Mar 2009 18:39:22 -0700
parents c771b7f43bbf
children bd441136a5ce
comparison
equal deleted inserted replaced
643:c771b7f43bbf 644:c517646eef23
7284 movl(scan_temp, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes())); 7284 movl(scan_temp, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes()));
7285 movptr(method_result, Address(recv_klass, scan_temp, Address::times_1)); 7285 movptr(method_result, Address(recv_klass, scan_temp, Address::times_1));
7286 } 7286 }
7287 7287
7288 7288
7289 void MacroAssembler::check_klass_subtype(Register sub_klass,
7290 Register super_klass,
7291 Register temp_reg,
7292 Label& L_success) {
7293 Label L_failure;
7294 check_klass_subtype_fast_path(sub_klass, super_klass, temp_reg, &L_success, &L_failure, NULL);
7295 check_klass_subtype_slow_path(sub_klass, super_klass, temp_reg, noreg, &L_success, NULL);
7296 bind(L_failure);
7297 }
7298
7299
7300 void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass,
7301 Register super_klass,
7302 Register temp_reg,
7303 Label* L_success,
7304 Label* L_failure,
7305 Label* L_slow_path,
7306 RegisterConstant super_check_offset) {
7307 assert_different_registers(sub_klass, super_klass, temp_reg);
7308 bool must_load_sco = (super_check_offset.constant_or_zero() == -1);
7309 if (super_check_offset.is_register()) {
7310 assert_different_registers(sub_klass, super_klass,
7311 super_check_offset.as_register());
7312 } else if (must_load_sco) {
7313 assert(temp_reg != noreg, "supply either a temp or a register offset");
7314 }
7315
7316 Label L_fallthrough;
7317 int label_nulls = 0;
7318 if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; }
7319 if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; }
7320 if (L_slow_path == NULL) { L_slow_path = &L_fallthrough; label_nulls++; }
7321 assert(label_nulls <= 1, "at most one NULL in the batch");
7322
7323 int sc_offset = (klassOopDesc::header_size() * HeapWordSize +
7324 Klass::secondary_super_cache_offset_in_bytes());
7325 int sco_offset = (klassOopDesc::header_size() * HeapWordSize +
7326 Klass::super_check_offset_offset_in_bytes());
7327 Address super_check_offset_addr(super_klass, sco_offset);
7328
7329 // Hacked jcc, which "knows" that L_fallthrough, at least, is in
7330 // range of a jccb. If this routine grows larger, reconsider at
7331 // least some of these.
7332 #define local_jcc(assembler_cond, label) \
7333 if (&(label) == &L_fallthrough) jccb(assembler_cond, label); \
7334 else jcc( assembler_cond, label) /*omit semi*/
7335
7336 // Hacked jmp, which may only be used just before L_fallthrough.
7337 #define final_jmp(label) \
7338 if (&(label) == &L_fallthrough) { /*do nothing*/ } \
7339 else jmp(label) /*omit semi*/
7340
7341 // If the pointers are equal, we are done (e.g., String[] elements).
7342 // This self-check enables sharing of secondary supertype arrays among
7343 // non-primary types such as array-of-interface. Otherwise, each such
7344 // type would need its own customized SSA.
7345 // We move this check to the front of the fast path because many
7346 // type checks are in fact trivially successful in this manner,
7347 // so we get a nicely predicted branch right at the start of the check.
7348 cmpptr(sub_klass, super_klass);
7349 local_jcc(Assembler::equal, *L_success);
7350
7351 // Check the supertype display:
7352 if (must_load_sco) {
7353 // Positive movl does right thing on LP64.
7354 movl(temp_reg, super_check_offset_addr);
7355 super_check_offset = RegisterConstant(temp_reg);
7356 }
7357 Address super_check_addr(sub_klass, super_check_offset, Address::times_1, 0);
7358 cmpptr(super_klass, super_check_addr); // load displayed supertype
7359
7360 // This check has worked decisively for primary supers.
7361 // Secondary supers are sought in the super_cache ('super_cache_addr').
7362 // (Secondary supers are interfaces and very deeply nested subtypes.)
7363 // This works in the same check above because of a tricky aliasing
7364 // between the super_cache and the primary super display elements.
7365 // (The 'super_check_addr' can address either, as the case requires.)
7366 // Note that the cache is updated below if it does not help us find
7367 // what we need immediately.
7368 // So if it was a primary super, we can just fail immediately.
7369 // Otherwise, it's the slow path for us (no success at this point).
7370
7371 if (super_check_offset.is_register()) {
7372 local_jcc(Assembler::equal, *L_success);
7373 cmpl(super_check_offset.as_register(), sc_offset);
7374 if (L_failure == &L_fallthrough) {
7375 local_jcc(Assembler::equal, *L_slow_path);
7376 } else {
7377 local_jcc(Assembler::notEqual, *L_failure);
7378 final_jmp(*L_slow_path);
7379 }
7380 } else if (super_check_offset.as_constant() == sc_offset) {
7381 // Need a slow path; fast failure is impossible.
7382 if (L_slow_path == &L_fallthrough) {
7383 local_jcc(Assembler::equal, *L_success);
7384 } else {
7385 local_jcc(Assembler::notEqual, *L_slow_path);
7386 final_jmp(*L_success);
7387 }
7388 } else {
7389 // No slow path; it's a fast decision.
7390 if (L_failure == &L_fallthrough) {
7391 local_jcc(Assembler::equal, *L_success);
7392 } else {
7393 local_jcc(Assembler::notEqual, *L_failure);
7394 final_jmp(*L_success);
7395 }
7396 }
7397
7398 bind(L_fallthrough);
7399
7400 #undef local_jcc
7401 #undef final_jmp
7402 }
7403
7404
7405 void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass,
7406 Register super_klass,
7407 Register temp_reg,
7408 Register temp2_reg,
7409 Label* L_success,
7410 Label* L_failure,
7411 bool set_cond_codes) {
7412 assert_different_registers(sub_klass, super_klass, temp_reg);
7413 if (temp2_reg != noreg)
7414 assert_different_registers(sub_klass, super_klass, temp_reg, temp2_reg);
7415 #define IS_A_TEMP(reg) ((reg) == temp_reg || (reg) == temp2_reg)
7416
7417 Label L_fallthrough;
7418 int label_nulls = 0;
7419 if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; }
7420 if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; }
7421 assert(label_nulls <= 1, "at most one NULL in the batch");
7422
7423 // a couple of useful fields in sub_klass:
7424 int ss_offset = (klassOopDesc::header_size() * HeapWordSize +
7425 Klass::secondary_supers_offset_in_bytes());
7426 int sc_offset = (klassOopDesc::header_size() * HeapWordSize +
7427 Klass::secondary_super_cache_offset_in_bytes());
7428 Address secondary_supers_addr(sub_klass, ss_offset);
7429 Address super_cache_addr( sub_klass, sc_offset);
7430
7431 // Do a linear scan of the secondary super-klass chain.
7432 // This code is rarely used, so simplicity is a virtue here.
7433 // The repne_scan instruction uses fixed registers, which we must spill.
7434 // Don't worry too much about pre-existing connections with the input regs.
7435
7436 assert(sub_klass != rax, "killed reg"); // killed by mov(rax, super)
7437 assert(sub_klass != rcx, "killed reg"); // killed by lea(rcx, &pst_counter)
7438
7439 // Get super_klass value into rax (even if it was in rdi or rcx).
7440 bool pushed_rax = false, pushed_rcx = false, pushed_rdi = false;
7441 if (super_klass != rax || UseCompressedOops) {
7442 if (!IS_A_TEMP(rax)) { push(rax); pushed_rax = true; }
7443 mov(rax, super_klass);
7444 }
7445 if (!IS_A_TEMP(rcx)) { push(rcx); pushed_rcx = true; }
7446 if (!IS_A_TEMP(rdi)) { push(rdi); pushed_rdi = true; }
7447
7448 #ifndef PRODUCT
7449 int* pst_counter = &SharedRuntime::_partial_subtype_ctr;
7450 ExternalAddress pst_counter_addr((address) pst_counter);
7451 NOT_LP64( incrementl(pst_counter_addr) );
7452 LP64_ONLY( lea(rcx, pst_counter_addr) );
7453 LP64_ONLY( incrementl(Address(rcx, 0)) );
7454 #endif //PRODUCT
7455
7456 // We will consult the secondary-super array.
7457 movptr(rdi, secondary_supers_addr);
7458 // Load the array length. (Positive movl does right thing on LP64.)
7459 movl(rcx, Address(rdi, arrayOopDesc::length_offset_in_bytes()));
7460 // Skip to start of data.
7461 addptr(rdi, arrayOopDesc::base_offset_in_bytes(T_OBJECT));
7462
7463 // Scan RCX words at [RDI] for an occurrence of RAX.
7464 // Set NZ/Z based on last compare.
7465 #ifdef _LP64
7466 // This part is tricky, as values in supers array could be 32 or 64 bit wide
7467 // and we store values in objArrays always encoded, thus we need to encode
7468 // the value of rax before repne. Note that rax is dead after the repne.
7469 if (UseCompressedOops) {
7470 encode_heap_oop_not_null(rax);
7471 // The superclass is never null; it would be a basic system error if a null
7472 // pointer were to sneak in here. Note that we have already loaded the
7473 // Klass::super_check_offset from the super_klass in the fast path,
7474 // so if there is a null in that register, we are already in the afterlife.
7475 repne_scanl();
7476 } else
7477 #endif // _LP64
7478 repne_scan();
7479
7480 // Unspill the temp. registers:
7481 if (pushed_rdi) pop(rdi);
7482 if (pushed_rcx) pop(rcx);
7483 if (pushed_rax) pop(rax);
7484
7485 if (set_cond_codes) {
7486 // Special hack for the AD files: rdi is guaranteed non-zero.
7487 assert(!pushed_rdi, "rdi must be left non-NULL");
7488 // Also, the condition codes are properly set Z/NZ on succeed/failure.
7489 }
7490
7491 if (L_failure == &L_fallthrough)
7492 jccb(Assembler::notEqual, *L_failure);
7493 else jcc(Assembler::notEqual, *L_failure);
7494
7495 // Success. Cache the super we found and proceed in triumph.
7496 movptr(super_cache_addr, super_klass);
7497
7498 if (L_success != &L_fallthrough) {
7499 jmp(*L_success);
7500 }
7501
7502 #undef IS_A_TEMP
7503
7504 bind(L_fallthrough);
7505 }
7506
7507
7289 void MacroAssembler::ucomisd(XMMRegister dst, AddressLiteral src) { 7508 void MacroAssembler::ucomisd(XMMRegister dst, AddressLiteral src) {
7290 ucomisd(dst, as_Address(src)); 7509 ucomisd(dst, as_Address(src));
7291 } 7510 }
7292 7511
7293 void MacroAssembler::ucomiss(XMMRegister dst, AddressLiteral src) { 7512 void MacroAssembler::ucomiss(XMMRegister dst, AddressLiteral src) {