Mercurial > hg > truffle
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) { |