void Jugador::Actualizar() { int x, y; get_mouse_mickeys(&x, &y); int dx, dy ; dx = orientacion.GetX() + y ; if ( dx < -85 ) { dx = -85 ; } if ( dx > 85 ) { dx = 85 ; } dy = ((int)(orientacion.GetY() + x))%360 ; orientacion.SetX(dx); orientacion.SetY(dy); Vector mov(0,0,0); if ( movimiento.GetY() > -0.1 ) { if ( key[KEY_UP] ) { mov.SetX(mov.GetX()+ 0.1 * cos((orientacion.GetY()-90)*PIOVER180) ); mov.SetZ(mov.GetZ()+ 0.1 * sin((orientacion.GetY()-90)*PIOVER180) ); } if ( key[KEY_DOWN] ) { mov.SetX(mov.GetX()+ 0.1 * cos((orientacion.GetY()+90)*PIOVER180) ); mov.SetZ(mov.GetZ()+ 0.1 * sin((orientacion.GetY()+90)*PIOVER180) ); } if ( key[KEY_RIGHT] ) { mov.SetX(mov.GetX()+ 0.1 * cos((orientacion.GetY())*PIOVER180) ); mov.SetZ(mov.GetZ()+ 0.1 * sin((orientacion.GetY())*PIOVER180) ); } if ( key[KEY_LEFT] ) { mov.SetX(mov.GetX()+ 0.1 * cos((orientacion.GetY()+180)*PIOVER180) ); mov.SetZ(mov.GetZ()+ 0.1 * sin((orientacion.GetY()+180)*PIOVER180) ); } } movimiento.SetX( mov.GetX() ); movimiento.SetZ( mov.GetZ() ); movimiento.SetY( movimiento.GetY() - 0.005 ); if ( movimiento.GetY() < -0.3 ) { velocidadMuerte = true ; } nivel->DesplazarItem(posicion, movimiento, radio); posicion = posicion + movimiento ; if ( ((movimiento.GetY() > -0.1 ) && velocidadMuerte) || posicion.GetY() < 0.0 ) { nivel->MuereJugador(); } }
address JNI_FastGetField::generate_fast_get_long_field() { const char *name = "jni_fast_GetLongField"; ResourceMark rm; BufferBlob* b = BufferBlob::create(name, BUFFER_SIZE*wordSize); address fast_entry = b->instructions_begin(); CodeBuffer cbuf(fast_entry, b->instructions_size()); MacroAssembler* masm = new MacroAssembler(&cbuf); Label slow; // stack layout: offset from rsp (in words): // old rsi 0 // return pc 1 // jni env 2 // obj 3 // jfieldID 4 ExternalAddress counter(SafepointSynchronize::safepoint_counter_addr()); __ push (rsi); __ mov32 (rcx, counter); __ testb (rcx, 1); __ jcc (Assembler::notZero, slow); if (os::is_MP()) { __ mov(rax, rcx); __ andptr(rax, 1); // rax, must end up 0 __ movptr(rdx, Address(rsp, rax, Address::times_1, 3*wordSize)); // obj, notice rax, is 0. // rdx is data dependent on rcx. } else { __ movptr(rdx, Address(rsp, 3*wordSize)); // obj } __ movptr(rsi, Address(rsp, 4*wordSize)); // jfieldID __ movptr(rdx, Address(rdx, 0)); // *obj __ shrptr(rsi, 2); // offset assert(count < LIST_CAPACITY-1, "LIST_CAPACITY too small"); speculative_load_pclist[count++] = __ pc(); __ movptr(rax, Address(rdx, rsi, Address::times_1)); #ifndef _LP64 speculative_load_pclist[count] = __ pc(); __ movl(rdx, Address(rdx, rsi, Address::times_1, 4)); #endif // _LP64 if (os::is_MP()) { __ lea(rsi, counter); __ xorptr(rsi, rdx); __ xorptr(rsi, rax); __ xorptr(rsi, rdx); __ xorptr(rsi, rax); __ cmp32(rcx, Address(rsi, 0)); // ca1 is the same as ca because // rax, ^ rdx ^ counter_addr ^ rax, ^ rdx = address // ca1 is data dependent on both rax, and rdx. } else { __ cmp32(rcx, counter); } __ jcc (Assembler::notEqual, slow); __ pop (rsi); #ifndef _WINDOWS __ ret (0); #else // __stdcall calling convention __ ret (3*wordSize); #endif slowcase_entry_pclist[count-1] = __ pc(); slowcase_entry_pclist[count++] = __ pc(); __ bind (slow); __ pop (rsi); address slow_case_addr = jni_GetLongField_addr();; // tail call __ jump (ExternalAddress(slow_case_addr)); __ flush (); #ifndef _WINDOWS return fast_entry; #else jni_fast_GetLongField_fp = (GetLongField_t)fast_entry; return os::win32::fast_jni_accessor_wrapper(T_LONG); #endif }
address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { const char *name; switch (type) { case T_BOOLEAN: name = "jni_fast_GetBooleanField"; break; case T_BYTE: name = "jni_fast_GetByteField"; break; case T_CHAR: name = "jni_fast_GetCharField"; break; case T_SHORT: name = "jni_fast_GetShortField"; break; case T_INT: name = "jni_fast_GetIntField"; break; default: ShouldNotReachHere(); } ResourceMark rm; BufferBlob* b = BufferBlob::create(name, BUFFER_SIZE*wordSize); address fast_entry = b->instructions_begin(); CodeBuffer cbuf(fast_entry, b->instructions_size()); MacroAssembler* masm = new MacroAssembler(&cbuf); Label slow; // stack layout: offset from rsp (in words): // return pc 0 // jni env 1 // obj 2 // jfieldID 3 ExternalAddress counter(SafepointSynchronize::safepoint_counter_addr()); __ mov32 (rcx, counter); __ testb (rcx, 1); __ jcc (Assembler::notZero, slow); if (os::is_MP()) { __ mov(rax, rcx); __ andptr(rax, 1); // rax, must end up 0 __ movptr(rdx, Address(rsp, rax, Address::times_1, 2*wordSize)); // obj, notice rax, is 0. // rdx is data dependent on rcx. } else { __ movptr (rdx, Address(rsp, 2*wordSize)); // obj } __ movptr(rax, Address(rsp, 3*wordSize)); // jfieldID __ movptr(rdx, Address(rdx, 0)); // *obj __ shrptr (rax, 2); // offset assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); speculative_load_pclist[count] = __ pc(); switch (type) { case T_BOOLEAN: __ movzbl (rax, Address(rdx, rax, Address::times_1)); break; case T_BYTE: __ movsbl (rax, Address(rdx, rax, Address::times_1)); break; case T_CHAR: __ movzwl (rax, Address(rdx, rax, Address::times_1)); break; case T_SHORT: __ movswl (rax, Address(rdx, rax, Address::times_1)); break; case T_INT: __ movl (rax, Address(rdx, rax, Address::times_1)); break; default: ShouldNotReachHere(); } Address ca1; if (os::is_MP()) { __ lea(rdx, counter); __ xorptr(rdx, rax); __ xorptr(rdx, rax); __ cmp32(rcx, Address(rdx, 0)); // ca1 is the same as ca because // rax, ^ counter_addr ^ rax, = address // ca1 is data dependent on rax,. } else { __ cmp32(rcx, counter); } __ jcc (Assembler::notEqual, slow); #ifndef _WINDOWS __ ret (0); #else // __stdcall calling convention __ ret (3*wordSize); #endif slowcase_entry_pclist[count++] = __ pc(); __ bind (slow); address slow_case_addr; switch (type) { case T_BOOLEAN: slow_case_addr = jni_GetBooleanField_addr(); break; case T_BYTE: slow_case_addr = jni_GetByteField_addr(); break; case T_CHAR: slow_case_addr = jni_GetCharField_addr(); break; case T_SHORT: slow_case_addr = jni_GetShortField_addr(); break; case T_INT: slow_case_addr = jni_GetIntField_addr(); } // tail call __ jump (ExternalAddress(slow_case_addr)); __ flush (); #ifndef _WINDOWS return fast_entry; #else switch (type) { case T_BOOLEAN: jni_fast_GetBooleanField_fp = (GetBooleanField_t)fast_entry; break; case T_BYTE: jni_fast_GetByteField_fp = (GetByteField_t)fast_entry; break; case T_CHAR: jni_fast_GetCharField_fp = (GetCharField_t)fast_entry; break; case T_SHORT: jni_fast_GetShortField_fp = (GetShortField_t)fast_entry; break; case T_INT: jni_fast_GetIntField_fp = (GetIntField_t)fast_entry; } return os::win32::fast_jni_accessor_wrapper(type); #endif }
void Constant::MoveToSlot(MacroAssembler* masm, SlotLocation* loc) { __ mov(ToOperand(loc), Immediate(handle_)); }
void SlotLocation::Set(MacroAssembler* masm, Register reg) { __ mov(ToOperand(this), reg); }
uint8_t* Assembler::emitCall(void* ptr, Register scratch) { mov(Immediate(ptr), scratch); callq(scratch); return addr; }
//------------------------------ generate_exception_blob --------------------------- // creates exception blob at the end // Using exception blob, this code is jumped from a compiled method. // (see emit_exception_handler in sparc.ad file) // // Given an exception pc at a call we call into the runtime for the // handler in this method. This handler might merely restore state // (i.e. callee save registers) unwind the frame and jump to the // exception handler for the nmethod if there is no Java level handler // for the nmethod. // // This code is entered with a jmp. // // Arguments: // O0: exception oop // O1: exception pc // // Results: // O0: exception oop // O1: exception pc in caller or ??? // destination: exception handler of caller // // Note: the exception pc MUST be at a call (precise debug information) // void OptoRuntime::generate_exception_blob() { // allocate space for code ResourceMark rm; int pad = VerifyThread ? 256 : 0;// Extra slop space for more verify code // setup code generation tools // Measured 8/7/03 at 256 in 32bit debug build (no VerifyThread) // Measured 8/7/03 at 528 in 32bit debug build (VerifyThread) CodeBuffer buffer("exception_blob", 600+pad, 512); MacroAssembler* masm = new MacroAssembler(&buffer); int framesize_in_bytes = __ total_frame_size_in_bytes(0); int framesize_in_words = framesize_in_bytes / wordSize; int framesize_in_slots = framesize_in_bytes / sizeof(jint); Label L; int start = __ offset(); __ verify_thread(); __ st_ptr(Oexception, G2_thread, JavaThread::exception_oop_offset()); __ st_ptr(Oissuing_pc, G2_thread, JavaThread::exception_pc_offset()); // This call does all the hard work. It checks if an exception catch // exists in the method. // If so, it returns the handler address. // If the nmethod has been deoptimized and it had a handler the handler // address is the deopt blob unpack_with_exception entry. // // If no handler exists it prepares for stack-unwinding, restoring the callee-save // registers of the frame being removed. // __ save_frame(0); __ mov(G2_thread, O0); __ set_last_Java_frame(SP, noreg); __ save_thread(L7_thread_cache); // This call can block at exit and nmethod can be deoptimized at that // point. If the nmethod had a catch point we would jump to the // now deoptimized catch point and fall thru the vanilla deopt // path and lose the exception // Sure would be simpler if this call didn't block! __ call(CAST_FROM_FN_PTR(address, OptoRuntime::handle_exception_C), relocInfo::runtime_call_type); __ delayed()->mov(L7_thread_cache, O0); // Set an oopmap for the call site. This oopmap will only be used if we // are unwinding the stack. Hence, all locations will be dead. // Callee-saved registers will be the same as the frame above (i.e., // handle_exception_stub), since they were restored when we got the // exception. OopMapSet *oop_maps = new OopMapSet(); oop_maps->add_gc_map( __ offset()-start, new OopMap(framesize_in_slots, 0)); __ bind(L); __ restore_thread(L7_thread_cache); __ reset_last_Java_frame(); __ mov(O0, G3_scratch); // Move handler address to temp __ restore(); // Restore SP from L7 if the exception PC is a MethodHandle call site. __ lduw(Address(G2_thread, JavaThread::is_method_handle_return_offset()), O7); __ tst(O7); __ movcc(Assembler::notZero, false, Assembler::icc, L7_mh_SP_save, SP); // G3_scratch contains handler address // Since this may be the deopt blob we must set O7 to look like we returned // from the original pc that threw the exception __ ld_ptr(G2_thread, JavaThread::exception_pc_offset(), O7); __ sub(O7, frame::pc_return_offset, O7); assert(Assembler::is_simm13(in_bytes(JavaThread::exception_oop_offset())), "exception offset overflows simm13, following ld instruction cannot be in delay slot"); __ ld_ptr(G2_thread, JavaThread::exception_oop_offset(), Oexception); // O0 #ifdef ASSERT __ st_ptr(G0, G2_thread, JavaThread::exception_handler_pc_offset()); __ st_ptr(G0, G2_thread, JavaThread::exception_pc_offset()); #endif __ JMP(G3_scratch, 0); // Clear the exception oop so GC no longer processes it as a root. __ delayed()->st_ptr(G0, G2_thread, JavaThread::exception_oop_offset()); // ------------- // make sure all code is generated masm->flush(); _exception_blob = ExceptionBlob::create(&buffer, oop_maps, framesize_in_words); }
address AbstractInterpreterGenerator::generate_slow_signature_handler() { address entry = __ pc(); // rbx: method // r14: pointer to locals // c_rarg3: first stack arg - wordSize __ mov(c_rarg3, rsp); // adjust rsp __ subptr(rsp, 4 * wordSize); __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::slow_signature_handler), rbx, r14, c_rarg3); // rax: result handler // Stack layout: // rsp: 3 integer or float args (if static first is unused) // 1 float/double identifiers // return address // stack args // garbage // expression stack bottom // bcp (NULL) // ... // Do FP first so we can use c_rarg3 as temp __ movl(c_rarg3, Address(rsp, 3 * wordSize)); // float/double identifiers for ( int i= 0; i < Argument::n_int_register_parameters_c-1; i++ ) { XMMRegister floatreg = as_XMMRegister(i+1); Label isfloatordouble, isdouble, next; __ testl(c_rarg3, 1 << (i*2)); // Float or Double? __ jcc(Assembler::notZero, isfloatordouble); // Do Int register here switch ( i ) { case 0: __ movl(rscratch1, Address(rbx, methodOopDesc::access_flags_offset())); __ testl(rscratch1, JVM_ACC_STATIC); __ cmovptr(Assembler::zero, c_rarg1, Address(rsp, 0)); break; case 1: __ movptr(c_rarg2, Address(rsp, wordSize)); break; case 2: __ movptr(c_rarg3, Address(rsp, 2 * wordSize)); break; default: break; } __ jmp (next); __ bind(isfloatordouble); __ testl(c_rarg3, 1 << ((i*2)+1)); // Double? __ jcc(Assembler::notZero, isdouble); // Do Float Here __ movflt(floatreg, Address(rsp, i * wordSize)); __ jmp(next); // Do Double here __ bind(isdouble); __ movdbl(floatreg, Address(rsp, i * wordSize)); __ bind(next); } // restore rsp __ addptr(rsp, 4 * wordSize); __ ret(0); return entry; }
inline Aabb& lower(const Point<> &aa) { mov(_a, aa); return *this; }
void InterpreterStubs::generate_primordial_to_current_thread() { Segment seg(this, code_segment, "Primordial to current thread"); bind_global("primordial_to_current_thread"); comment("save permanent registers (including return address)"); stmfd(sp, range(r3, r11), writeback); str(lr, imm_index(sp, -BytesPerWord, pre_indexed)); comment("Set up global pointer"); ldr_gp_base(gp); comment("Get current thread"); get_thread(r1); comment("Save primordial stack pointer"); set_primordial_sp(sp); comment("Get new stack pointer"); ldr(jsp, imm_index(r1, Thread::stack_pointer_offset())); comment("Go to code"); ldr(lr, imm_index(jsp, -JavaStackDirection * BytesPerWord)); ldr(fp, imm_index(jsp, -JavaStackDirection * 2 * BytesPerWord, post_indexed)); jmpx(lr); bind_global("start_lightweight_thread_asm"); Label testing_compiler; const int SignedBytesPerWord = JavaStackDirection * BytesPerWord; comment("Set up global pointer"); ldr_gp_base(gp); // jsp => Thread::lightweight_thread_exit // jsp +- 4 => Thread::lightweight_thread_uncaught_exception // jsp +- 8 => Thread::finish // jsp +- 12 => force_terminated // jsp +- 16 => TestCompiler comment("Invoke pending entries unless the thread is being terminated"); get_thread(r0); comment("r1 = THREAD->status();"); ldr(r1, imm_index(r0, Thread::status_offset())); mov(r2, zero); comment("if ((r1 & THREAD_TERMINATING) != 0) {"); tst(r1, imm(THREAD_TERMINATING)); comment(" THREAD->pending_entries = NULL;"); str(r2, imm_index(r0, Thread::pending_entries_offset()), ne); comment("} else {"); comment(" invoke_pending_entries(THREAD)"); bl("invoke_pending_entries", eq); comment("}"); comment("if (!TestCompiler) {"); ldr(r0, imm_index(jsp, -4 * SignedBytesPerWord)); get_current_pending_exception(r1); cmp(r0, zero); b(testing_compiler, ne); comment(" if (Thread::current_has_pending_exception()) {"); comment(" call_on_primordial_stack(lightweight_thread_uncaught_exception);"); comment(" }"); cmp(r1, zero); ldr(r0, imm_index(jsp, -1 * SignedBytesPerWord), ne); bl("call_on_primordial_stack", ne); comment(" call_on_primordial_stack(finish);"); ldr(r0, imm_index(jsp, -2 * SignedBytesPerWord)); bl("call_on_primordial_stack"); comment(" invoke_pending_entries(THREAD);"); get_thread(r0); bl("invoke_pending_entries"); comment(" force_terminated()"); ldr(r0, imm_index(jsp, -3 * SignedBytesPerWord)); bl("call_on_primordial_stack"); comment("}"); #if ENABLE_ISOLATES comment("Terminate the task if no other threads on it"); ldr_label(r0, "thread_task_cleanup"); bl("call_on_primordial_stack"); comment(" invoke_pending_entries(THREAD);"); get_thread(r0); bl("invoke_pending_entries"); #endif bind_global(testing_compiler); comment("call_on_primordial_stack(lightweight_thread_exit);"); ldr(r0, imm_index(jsp)); bl("call_on_primordial_stack"); comment("GUARANTEE(Scheduler::_next_runnable_thread == NULL"); ldr_label(r0, "_next_runnable_thread"); ldr(r0, imm_index(r0)); cmp(r0, zero); breakpoint(ne); comment("current_thread_to_primordial();"); bl("current_thread_to_primordial_fast"); breakpoint(); }
void InterpreterStubs::generate_interpreter_fill_in_tags() { Segment seg(this, code_segment, "Interpreter fill in tags"); Register param_size = tmp0; // must be preserved Register callinfo = tmp1; { bind_local("interpreter_fill_in_tags"); comment("%s: size of parameters", reg_name(tmp0)); comment("%s: call info from call size", reg_name(tmp1)); comment(""); comment("Must preserve lr, %s (method), and %s (parameter size)", reg_name(r0), reg_name(tmp0)); Label loop_entry; // tos_val = r0 must be preserved Register arg_index = tmp2; Register one_reg = tmp3; Register tag_address = JavaStackDirection < 0 ? tmp4 : jsp; mov_imm(one_reg, 1 << CallInfo::format1_tag_start); sub(arg_index, param_size, one, set_CC); report_fatal("shouldn't be called on no arguments", lt); if (JavaStackDirection < 0) { comment("Tag address of last argument"); add(tag_address, jsp, imm(BytesPerWord)); } else { comment("jsp points to tag address of last argument"); } bind(loop_entry); comment("test the bit in the call info"); tst(callinfo, reg_shift(one_reg, lsl, arg_index)); mov(tos_tag, imm(obj_tag), ne); mov(tos_tag, imm(int_tag), eq); if (JavaStackDirection < 0) { str(tos_tag, add_index(tag_address, arg_index, lsl, 3)); } else { str(tos_tag, sub_index(tag_address, arg_index, lsl, 3)); } sub(arg_index, arg_index, one, set_CC); b(loop_entry, ge); mov(pc, reg(locals)); } { Register bit_offset = tmp1; // callinfo not needed Register one_reg = tmp2; Register tag_address = tmp3; Register x1 = tmp4; Register x2 = tmp5; Register index = tos_tag; Label loop; bind_local("interpreter_fill_in_extended_tags"); comment("Total number of tags"); if (HARDWARE_LITTLE_ENDIAN) { ldrh(bit_offset, imm_index3(lr, -2 * BytesPerWord)); } else { ldrh(bit_offset, imm_index3(lr, -2 * BytesPerWord + 2)); } comment("Tag address of first argument"); if (JavaStackDirection < 0) { add(tag_address, jsp, imm_shift(param_size, lsl, 3)); } else { sub(tag_address, jsp, imm_shift(param_size, lsl, 3)); } // tag_address points to the last address of the previous stack add_imm(tag_address, tag_address, JavaFrame::arg_offset_from_sp(-1) + BytesPerWord); comment("Index of last argument"); sub(index, param_size, one); comment("Bit number of first argument"); sub(bit_offset, bit_offset, reg(param_size)); mov(bit_offset, imm_shift(bit_offset, lsl, 2)); add(bit_offset, bit_offset, imm(32 + 32 + 16)); comment("A useful constant"); mov(one_reg, one); bind(loop); comment("Get the bit offset for this argument"); add(x1, bit_offset, imm_shift(index, lsl, 2)); comment("Get the appropriate word"); mov(x2, imm_shift(x1, lsr, 5)); ldr(x2, sub_index(lr, x2, lsl, 2)); comment("Pick out the nybble"); andr(x1, x1, imm(31)); mov(x2, reg_shift(x2, lsr, x1)); andr(x2, x2, imm(15), set_CC); comment("Convert the nybble into a stack type"); sub(x2, x2, one, ne); mov(x2, reg_shift(one_reg, lsl, x2), ne); if (JavaStackDirection < 0) { str(x2, sub_index(tag_address, index, lsl, 3)); } else { str(x2, add_index(tag_address, index, lsl, 3)); } comment("Update the info"); sub(index, index, one, set_CC); b(loop, ge); mov(pc, reg(locals)); } }
address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { const char *name; switch (type) { case T_BOOLEAN: name = "jni_fast_GetBooleanField"; break; case T_BYTE: name = "jni_fast_GetByteField"; break; case T_CHAR: name = "jni_fast_GetCharField"; break; case T_SHORT: name = "jni_fast_GetShortField"; break; case T_INT: name = "jni_fast_GetIntField"; break; case T_LONG: name = "jni_fast_GetLongField"; break; case T_FLOAT: name = "jni_fast_GetFloatField"; break; case T_DOUBLE: name = "jni_fast_GetDoubleField"; break; default: ShouldNotReachHere(); } ResourceMark rm; BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE); CodeBuffer cbuf(blob); MacroAssembler* masm = new MacroAssembler(&cbuf); address fast_entry = __ pc(); Label slow; unsigned long offset; __ adrp(rcounter_addr, SafepointSynchronize::safepoint_counter_addr(), offset); Address safepoint_counter_addr(rcounter_addr, offset); __ ldrw(rcounter, safepoint_counter_addr); __ andw(rscratch1, rcounter, 1); __ cbnzw(rscratch1, slow); __ eor(robj, c_rarg1, rcounter); __ eor(robj, robj, rcounter); // obj, since // robj ^ rcounter ^ rcounter == robj // robj is address dependent on rcounter. __ ldr(robj, Address(robj, 0)); // *obj __ lsr(roffset, c_rarg2, 2); // offset assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); speculative_load_pclist[count] = __ pc(); // Used by the segfault handler switch (type) { case T_BOOLEAN: __ ldrb (result, Address(robj, roffset)); break; case T_BYTE: __ ldrsb (result, Address(robj, roffset)); break; case T_CHAR: __ ldrh (result, Address(robj, roffset)); break; case T_SHORT: __ ldrsh (result, Address(robj, roffset)); break; case T_FLOAT: __ ldrw (result, Address(robj, roffset)); break; case T_INT: __ ldrsw (result, Address(robj, roffset)); break; case T_DOUBLE: case T_LONG: __ ldr (result, Address(robj, roffset)); break; default: ShouldNotReachHere(); } // counter_addr is address dependent on result. __ eor(rcounter_addr, rcounter_addr, result); __ eor(rcounter_addr, rcounter_addr, result); __ ldrw(rscratch1, safepoint_counter_addr); __ cmpw(rcounter, rscratch1); __ br (Assembler::NE, slow); switch (type) { case T_FLOAT: __ fmovs(v0, result); break; case T_DOUBLE: __ fmovd(v0, result); break; default: __ mov(r0, result); break; } __ ret(lr); slowcase_entry_pclist[count++] = __ pc(); __ bind(slow); address slow_case_addr; switch (type) { case T_BOOLEAN: slow_case_addr = jni_GetBooleanField_addr(); break; case T_BYTE: slow_case_addr = jni_GetByteField_addr(); break; case T_CHAR: slow_case_addr = jni_GetCharField_addr(); break; case T_SHORT: slow_case_addr = jni_GetShortField_addr(); break; case T_INT: slow_case_addr = jni_GetIntField_addr(); break; case T_LONG: slow_case_addr = jni_GetLongField_addr(); break; case T_FLOAT: slow_case_addr = jni_GetFloatField_addr(); break; case T_DOUBLE: slow_case_addr = jni_GetDoubleField_addr(); break; default: ShouldNotReachHere(); } { __ enter(); __ lea(rscratch1, ExternalAddress(slow_case_addr)); __ blr(rscratch1); __ maybe_isb(); __ leave(); __ ret(lr); } __ flush (); return fast_entry; }
static char* gen_invoke_common_managed_func(char* stub) { // Defines stack alignment on managed function enter. const I_32 STACK_ALIGNMENT = MANAGED_STACK_ALIGNMENT; const I_32 STACK_ALIGNMENT_MASK = ~(STACK_ALIGNMENT - 1); const char * LOOP_BEGIN = "loop_begin"; const char * LOOP_END = "loop_end"; // [ebp + 8] - args // [ebp + 12] - size // [ebp + 16] - func const I_32 STACK_ARGS_OFFSET = 8; const I_32 STACK_NARGS_OFFSET = 12; const I_32 STACK_FUNC_OFFSET = 16; const I_32 STACK_CALLEE_SAVED_OFFSET = -12; tl::MemoryPool pool; LilCguLabelAddresses labels(&pool, stub); // Initialize ebp-based stack frame. stub = push(stub, ebp_opnd); stub = mov(stub, ebp_opnd, esp_opnd); // Preserve callee-saved registers. stub = push(stub, ebx_opnd); stub = push(stub, esi_opnd); stub = push(stub, edi_opnd); // Load an array of arguments ('args') and its size from the stack. stub = mov(stub, eax_opnd, M_Base_Opnd(ebp_reg, STACK_ARGS_OFFSET)); stub = mov(stub, ecx_opnd, M_Base_Opnd(ebp_reg, STACK_NARGS_OFFSET)); // Align memory stack. stub = lea(stub, ebx_opnd, M_Index_Opnd(n_reg, ecx_reg, 4, 4)); stub = mov(stub, esi_opnd, ebx_opnd); stub = neg(stub, esi_opnd); stub = alu(stub, add_opc, esi_opnd, esp_opnd); stub = alu(stub, and_opc, esi_opnd, Imm_Opnd(size_32, STACK_ALIGNMENT_MASK)); stub = alu(stub, add_opc, ebx_opnd, esi_opnd); stub = mov(stub, esp_opnd, ebx_opnd); // Load a pointer to the last argument of 'args' array. stub = lea(stub, eax_opnd, M_Index_Opnd(eax_reg, ecx_reg, -4, 4)); stub = alu(stub, sub_opc, eax_opnd, esp_opnd); stub = alu(stub, or_opc, ecx_opnd, ecx_opnd); stub = branch8(stub, Condition_Z, Imm_Opnd(size_8, 0)); labels.add_patch_to_label(LOOP_END, stub - 1, LPT_Rel8); // LOOP_BEGIN: // Push inputs on the stack. labels.define_label(LOOP_BEGIN, stub, false); stub = push(stub, M_Index_Opnd(esp_reg, eax_reg, 0, 1)); stub = loop(stub, Imm_Opnd(size_8, 0)); labels.add_patch_to_label(LOOP_BEGIN, stub - 1, LPT_Rel8); // LOOP_END: labels.define_label(LOOP_END, stub, false); // Call target function. stub = mov(stub, eax_opnd, M_Base_Opnd(ebp_reg, STACK_FUNC_OFFSET)); stub = call(stub, eax_opnd); // Restore callee-saved registers from the stack. stub = lea(stub, esp_opnd, M_Base_Opnd(ebp_reg, STACK_CALLEE_SAVED_OFFSET)); stub = pop(stub, edi_opnd); stub = pop(stub, esi_opnd); stub = pop(stub, ebx_opnd); // Leave current frame. stub = pop(stub, ebp_opnd); return stub; }
OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler* sasm) { __ block_comment("generate_handle_exception"); // Save registers, if required. OopMapSet* oop_maps = new OopMapSet(); OopMap* oop_map = NULL; switch (id) { case forward_exception_id: // We're handling an exception in the context of a compiled frame. // The registers have been saved in the standard places. Perform // an exception lookup in the caller and dispatch to the handler // if found. Otherwise unwind and dispatch to the callers // exception handler. oop_map = generate_oop_map(sasm, true); // transfer the pending exception to the exception_oop __ ld_ptr(G2_thread, in_bytes(JavaThread::pending_exception_offset()), Oexception); __ ld_ptr(Oexception, 0, G0); __ st_ptr(G0, G2_thread, in_bytes(JavaThread::pending_exception_offset())); __ add(I7, frame::pc_return_offset, Oissuing_pc); break; case handle_exception_id: // At this point all registers MAY be live. oop_map = save_live_registers(sasm); __ mov(Oexception->after_save(), Oexception); __ mov(Oissuing_pc->after_save(), Oissuing_pc); break; case handle_exception_from_callee_id: // At this point all registers except exception oop (Oexception) // and exception pc (Oissuing_pc) are dead. oop_map = new OopMap(frame_size_in_bytes / sizeof(jint), 0); sasm->set_frame_size(frame_size_in_bytes / BytesPerWord); __ save_frame_c1(frame_size_in_bytes); __ mov(Oexception->after_save(), Oexception); __ mov(Oissuing_pc->after_save(), Oissuing_pc); break; default: ShouldNotReachHere(); } __ verify_not_null_oop(Oexception); // save the exception and issuing pc in the thread __ st_ptr(Oexception, G2_thread, in_bytes(JavaThread::exception_oop_offset())); __ st_ptr(Oissuing_pc, G2_thread, in_bytes(JavaThread::exception_pc_offset())); // use the throwing pc as the return address to lookup (has bci & oop map) __ mov(Oissuing_pc, I7); __ sub(I7, frame::pc_return_offset, I7); int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, exception_handler_for_pc)); oop_maps->add_gc_map(call_offset, oop_map); // Note: if nmethod has been deoptimized then regardless of // whether it had a handler or not we will deoptimize // by entering the deopt blob with a pending exception. // Restore the registers that were saved at the beginning, remove // the frame and jump to the exception handler. switch (id) { case forward_exception_id: case handle_exception_id: restore_live_registers(sasm); __ jmp(O0, 0); __ delayed()->restore(); break; case handle_exception_from_callee_id: // Restore SP from L7 if the exception PC is a method handle call site. __ mov(O0, G5); // Save the target address. __ lduw(Address(G2_thread, JavaThread::is_method_handle_return_offset()), L0); __ tst(L0); // Condition codes are preserved over the restore. __ restore(); __ jmp(G5, 0); // jump to the exception handler __ delayed()->movcc(Assembler::notZero, false, Assembler::icc, L7_mh_SP_save, SP); // Restore SP if required. break; default: ShouldNotReachHere(); } return oop_maps; }
address JNI_FastGetField::generate_fast_get_long_field() { const char *name = "jni_fast_GetLongField"; ResourceMark rm; BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE*wordSize); CodeBuffer cbuf(blob); MacroAssembler* masm = new MacroAssembler(&cbuf); address fast_entry = __ pc(); Label label1, label2; AddressLiteral cnt_addrlit(SafepointSynchronize::safepoint_counter_addr()); __ sethi (cnt_addrlit, G3); Address cnt_addr(G3, cnt_addrlit.low10()); __ ld (cnt_addr, G4); __ andcc (G4, 1, G0); __ br (Assembler::notZero, false, Assembler::pn, label1); __ delayed()->srl (O2, 2, O4); __ ld_ptr (O1, 0, O5); __ add (O5, O4, O5); #ifndef _LP64 assert(count < LIST_CAPACITY-1, "LIST_CAPACITY too small"); speculative_load_pclist[count++] = __ pc(); __ ld (O5, 0, G2); speculative_load_pclist[count] = __ pc(); __ ld (O5, 4, O3); #else assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); speculative_load_pclist[count] = __ pc(); __ ldx (O5, 0, O3); #endif __ ld (cnt_addr, G1); __ cmp (G1, G4); __ br (Assembler::notEqual, false, Assembler::pn, label2); __ delayed()->mov (O7, G1); #ifndef _LP64 __ mov (G2, O0); __ retl (); __ delayed()->mov (O3, O1); #else __ retl (); __ delayed()->mov (O3, O0); #endif #ifndef _LP64 slowcase_entry_pclist[count-1] = __ pc(); slowcase_entry_pclist[count++] = __ pc() ; #else slowcase_entry_pclist[count++] = __ pc(); #endif __ bind (label1); __ mov (O7, G1); address slow_case_addr = jni_GetLongField_addr(); __ bind (label2); __ call (slow_case_addr, relocInfo::none); __ delayed()->mov (G1, O7); __ flush (); return fast_entry; }
inline Aabb& upper(const Point<> &bb) { mov(_b, bb); return *this; }
address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { const char *name; switch (type) { case T_BOOLEAN: name = "jni_fast_GetBooleanField"; break; case T_BYTE: name = "jni_fast_GetByteField"; break; case T_CHAR: name = "jni_fast_GetCharField"; break; case T_SHORT: name = "jni_fast_GetShortField"; break; case T_INT: name = "jni_fast_GetIntField"; break; default: ShouldNotReachHere(); } ResourceMark rm; BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE*wordSize); CodeBuffer cbuf(blob); MacroAssembler* masm = new MacroAssembler(&cbuf); address fast_entry = __ pc(); Label label1, label2; AddressLiteral cnt_addrlit(SafepointSynchronize::safepoint_counter_addr()); __ sethi (cnt_addrlit, O3); Address cnt_addr(O3, cnt_addrlit.low10()); __ ld (cnt_addr, G4); __ andcc (G4, 1, G0); __ br (Assembler::notZero, false, Assembler::pn, label1); __ delayed()->srl (O2, 2, O4); __ ld_ptr (O1, 0, O5); assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); speculative_load_pclist[count] = __ pc(); switch (type) { case T_BOOLEAN: __ ldub (O5, O4, G3); break; case T_BYTE: __ ldsb (O5, O4, G3); break; case T_CHAR: __ lduh (O5, O4, G3); break; case T_SHORT: __ ldsh (O5, O4, G3); break; case T_INT: __ ld (O5, O4, G3); break; default: ShouldNotReachHere(); } __ ld (cnt_addr, O5); __ cmp (O5, G4); __ br (Assembler::notEqual, false, Assembler::pn, label2); __ delayed()->mov (O7, G1); __ retl (); __ delayed()->mov (G3, O0); slowcase_entry_pclist[count++] = __ pc(); __ bind (label1); __ mov (O7, G1); address slow_case_addr; switch (type) { case T_BOOLEAN: slow_case_addr = jni_GetBooleanField_addr(); break; case T_BYTE: slow_case_addr = jni_GetByteField_addr(); break; case T_CHAR: slow_case_addr = jni_GetCharField_addr(); break; case T_SHORT: slow_case_addr = jni_GetShortField_addr(); break; case T_INT: slow_case_addr = jni_GetIntField_addr(); break; default: ShouldNotReachHere(); } __ bind (label2); __ call (slow_case_addr, relocInfo::none); __ delayed()->mov (G1, O7); __ flush (); return fast_entry; }
int StubAssembler::call_RT(Register oop_result1, Register oop_result2, address entry, Register arg1) { // O0 is reserved for the thread mov(arg1, O1); return call_RT(oop_result1, oop_result2, entry, 1); }
address InterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) { // rbx,: methodOop // rcx: scratrch // rsi: sender sp if (!InlineIntrinsics) return NULL; // Generate a vanilla entry address entry_point = __ pc(); // These don't need a safepoint check because they aren't virtually // callable. We won't enter these intrinsics from compiled code. // If in the future we added an intrinsic which was virtually callable // we'd have to worry about how to safepoint so that this code is used. // mathematical functions inlined by compiler // (interpreter must provide identical implementation // in order to avoid monotonicity bugs when switching // from interpreter to compiler in the middle of some // computation) // // stack: [ ret adr ] <-- rsp // [ lo(arg) ] // [ hi(arg) ] // // Note: For JDK 1.2 StrictMath doesn't exist and Math.sin/cos/sqrt are // native methods. Interpreter::method_kind(...) does a check for // native methods first before checking for intrinsic methods and // thus will never select this entry point. Make sure it is not // called accidentally since the SharedRuntime entry points will // not work for JDK 1.2. // // We no longer need to check for JDK 1.2 since it's EOL'ed. // The following check existed in pre 1.6 implementation, // if (Universe::is_jdk12x_version()) { // __ should_not_reach_here(); // } // Universe::is_jdk12x_version() always returns false since // the JDK version is not yet determined when this method is called. // This method is called during interpreter_init() whereas // JDK version is only determined when universe2_init() is called. // Note: For JDK 1.3 StrictMath exists and Math.sin/cos/sqrt are // java methods. Interpreter::method_kind(...) will select // this entry point for the corresponding methods in JDK 1.3. // get argument __ fld_d(Address(rsp, 1*wordSize)); switch (kind) { case Interpreter::java_lang_math_sin : __ trigfunc('s'); break; case Interpreter::java_lang_math_cos : __ trigfunc('c'); break; case Interpreter::java_lang_math_tan : __ trigfunc('t'); break; case Interpreter::java_lang_math_sqrt: __ fsqrt(); break; case Interpreter::java_lang_math_abs: __ fabs(); break; case Interpreter::java_lang_math_log: __ flog(); // Store to stack to convert 80bit precision back to 64bits __ push_fTOS(); __ pop_fTOS(); break; case Interpreter::java_lang_math_log10: __ flog10(); // Store to stack to convert 80bit precision back to 64bits __ push_fTOS(); __ pop_fTOS(); break; default : ShouldNotReachHere(); } // return double result in xmm0 for interpreter and compilers. if (UseSSE >= 2) { __ subptr(rsp, 2*wordSize); __ fstp_d(Address(rsp, 0)); __ movdbl(xmm0, Address(rsp, 0)); __ addptr(rsp, 2*wordSize); } // done, result in FPU ST(0) or XMM0 __ pop(rdi); // get return address __ mov(rsp, rsi); // set sp to sender sp __ jmp(rdi); return entry_point; }
int StubAssembler::call_RT(Register oop_result1, Register oop_result2, address entry, Register arg1, Register arg2) { // O0 is reserved for the thread mov(arg1, O1); mov(arg2, O2); assert(arg2 != O1, "smashed argument"); return call_RT(oop_result1, oop_result2, entry, 2); }
void Constant::Get(MacroAssembler* masm, Register reg) { __ mov(reg, Immediate(handle_)); }
int StubAssembler::call_RT(Register oop_result1, Register oop_result2, address entry_point, int number_of_arguments) { // for sparc changing the number of arguments doesn't change // anything about the frame size so we'll always lie and claim that // we are only passing 1 argument. set_num_rt_args(1); assert_not_delayed(); // bang stack before going to runtime set(-os::vm_page_size() + STACK_BIAS, G3_scratch); st(G0, SP, G3_scratch); // debugging support assert(number_of_arguments >= 0 , "cannot have negative number of arguments"); set_last_Java_frame(SP, noreg); if (VerifyThread) mov(G2_thread, O0); // about to be smashed; pass early save_thread(L7_thread_cache); // do the call call(entry_point, relocInfo::runtime_call_type); if (!VerifyThread) { delayed()->mov(G2_thread, O0); // pass thread as first argument } else { delayed()->nop(); // (thread already passed) } int call_offset = offset(); // offset of return address restore_thread(L7_thread_cache); reset_last_Java_frame(); // check for pending exceptions { Label L; Address exception_addr(G2_thread, Thread::pending_exception_offset()); ld_ptr(exception_addr, Gtemp); br_null(Gtemp, false, pt, L); delayed()->nop(); Address vm_result_addr(G2_thread, JavaThread::vm_result_offset()); st_ptr(G0, vm_result_addr); Address vm_result_addr_2(G2_thread, JavaThread::vm_result_2_offset()); st_ptr(G0, vm_result_addr_2); if (frame_size() == no_frame_size) { // we use O7 linkage so that forward_exception_entry has the issuing PC call(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type); delayed()->restore(); } else if (_stub_id == Runtime1::forward_exception_id) { should_not_reach_here(); } else { AddressLiteral exc(Runtime1::entry_for(Runtime1::forward_exception_id)); jump_to(exc, G4); delayed()->nop(); } bind(L); } // get oop result if there is one and reset the value in the thread if (oop_result1->is_valid()) { // get oop result if there is one and reset it in the thread get_vm_result (oop_result1); } else { // be a little paranoid and clear the result Address vm_result_addr(G2_thread, JavaThread::vm_result_offset()); st_ptr(G0, vm_result_addr); } if (oop_result2->is_valid()) { get_vm_result_2(oop_result2); } else { // be a little paranoid and clear the result Address vm_result_addr_2(G2_thread, JavaThread::vm_result_2_offset()); st_ptr(G0, vm_result_addr_2); } return call_offset; }
void SlotLocation::Get(MacroAssembler* masm, Register reg) { __ mov(reg, ToOperand(this)); }
OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { OopMapSet* oop_maps = NULL; // for better readability const bool must_gc_arguments = true; const bool dont_gc_arguments = false; // stub code & info for the different stubs switch (id) { case forward_exception_id: { // we're handling an exception in the context of a compiled // frame. The registers have been saved in the standard // places. Perform an exception lookup in the caller and // dispatch to the handler if found. Otherwise unwind and // dispatch to the callers exception handler. oop_maps = new OopMapSet(); OopMap* oop_map = generate_oop_map(sasm, true); // transfer the pending exception to the exception_oop __ ld_ptr(G2_thread, in_bytes(JavaThread::pending_exception_offset()), Oexception); __ ld_ptr(Oexception, 0, G0); __ st_ptr(G0, G2_thread, in_bytes(JavaThread::pending_exception_offset())); __ add(I7, frame::pc_return_offset, Oissuing_pc); generate_handle_exception(sasm, oop_maps, oop_map); __ should_not_reach_here(); } break; case new_instance_id: case fast_new_instance_id: case fast_new_instance_init_check_id: { Register G5_klass = G5; // Incoming Register O0_obj = O0; // Outgoing if (id == new_instance_id) { __ set_info("new_instance", dont_gc_arguments); } else if (id == fast_new_instance_id) { __ set_info("fast new_instance", dont_gc_arguments); } else { assert(id == fast_new_instance_init_check_id, "bad StubID"); __ set_info("fast new_instance init check", dont_gc_arguments); } if ((id == fast_new_instance_id || id == fast_new_instance_init_check_id) && UseTLAB && FastTLABRefill) { Label slow_path; Register G1_obj_size = G1; Register G3_t1 = G3; Register G4_t2 = G4; assert_different_registers(G5_klass, G1_obj_size, G3_t1, G4_t2); // Push a frame since we may do dtrace notification for the // allocation which requires calling out and we don't want // to stomp the real return address. __ save_frame(0); if (id == fast_new_instance_init_check_id) { // make sure the klass is initialized __ ld(G5_klass, instanceKlass::init_state_offset_in_bytes() + sizeof(oopDesc), G3_t1); __ cmp(G3_t1, instanceKlass::fully_initialized); __ br(Assembler::notEqual, false, Assembler::pn, slow_path); __ delayed()->nop(); } #ifdef ASSERT // assert object can be fast path allocated { Label ok, not_ok; __ ld(G5_klass, Klass::layout_helper_offset_in_bytes() + sizeof(oopDesc), G1_obj_size); __ cmp(G1_obj_size, 0); // make sure it's an instance (LH > 0) __ br(Assembler::lessEqual, false, Assembler::pn, not_ok); __ delayed()->nop(); __ btst(Klass::_lh_instance_slow_path_bit, G1_obj_size); __ br(Assembler::zero, false, Assembler::pn, ok); __ delayed()->nop(); __ bind(not_ok); __ stop("assert(can be fast path allocated)"); __ should_not_reach_here(); __ bind(ok); } #endif // ASSERT // if we got here then the TLAB allocation failed, so try // refilling the TLAB or allocating directly from eden. Label retry_tlab, try_eden; __ tlab_refill(retry_tlab, try_eden, slow_path); // preserves G5_klass __ bind(retry_tlab); // get the instance size __ ld(G5_klass, klassOopDesc::header_size() * HeapWordSize + Klass::layout_helper_offset_in_bytes(), G1_obj_size); __ tlab_allocate(O0_obj, G1_obj_size, 0, G3_t1, slow_path); __ initialize_object(O0_obj, G5_klass, G1_obj_size, 0, G3_t1, G4_t2); __ verify_oop(O0_obj); __ mov(O0, I0); __ ret(); __ delayed()->restore(); __ bind(try_eden); // get the instance size __ ld(G5_klass, klassOopDesc::header_size() * HeapWordSize + Klass::layout_helper_offset_in_bytes(), G1_obj_size); __ eden_allocate(O0_obj, G1_obj_size, 0, G3_t1, G4_t2, slow_path); __ initialize_object(O0_obj, G5_klass, G1_obj_size, 0, G3_t1, G4_t2); __ verify_oop(O0_obj); __ mov(O0, I0); __ ret(); __ delayed()->restore(); __ bind(slow_path); // pop this frame so generate_stub_call can push it's own __ restore(); } oop_maps = generate_stub_call(sasm, I0, CAST_FROM_FN_PTR(address, new_instance), G5_klass); // I0->O0: new instance } break; #ifdef TIERED case counter_overflow_id: // G4 contains bci oop_maps = generate_stub_call(sasm, noreg, CAST_FROM_FN_PTR(address, counter_overflow), G4); break; #endif // TIERED case new_type_array_id: case new_object_array_id: { Register G5_klass = G5; // Incoming Register G4_length = G4; // Incoming Register O0_obj = O0; // Outgoing Address klass_lh(G5_klass, ((klassOopDesc::header_size() * HeapWordSize) + Klass::layout_helper_offset_in_bytes())); assert(Klass::_lh_header_size_shift % BitsPerByte == 0, "bytewise"); assert(Klass::_lh_header_size_mask == 0xFF, "bytewise"); // Use this offset to pick out an individual byte of the layout_helper: const int klass_lh_header_size_offset = ((BytesPerInt - 1) // 3 - 2 selects byte {0,1,0,0} - Klass::_lh_header_size_shift / BitsPerByte); if (id == new_type_array_id) { __ set_info("new_type_array", dont_gc_arguments); } else { __ set_info("new_object_array", dont_gc_arguments); } #ifdef ASSERT // assert object type is really an array of the proper kind { Label ok; Register G3_t1 = G3; __ ld(klass_lh, G3_t1); __ sra(G3_t1, Klass::_lh_array_tag_shift, G3_t1); int tag = ((id == new_type_array_id) ? Klass::_lh_array_tag_type_value : Klass::_lh_array_tag_obj_value); __ cmp(G3_t1, tag); __ brx(Assembler::equal, false, Assembler::pt, ok); __ delayed()->nop(); __ stop("assert(is an array klass)"); __ should_not_reach_here(); __ bind(ok); } #endif // ASSERT if (UseTLAB && FastTLABRefill) { Label slow_path; Register G1_arr_size = G1; Register G3_t1 = G3; Register O1_t2 = O1; assert_different_registers(G5_klass, G4_length, G1_arr_size, G3_t1, O1_t2); // check that array length is small enough for fast path __ set(C1_MacroAssembler::max_array_allocation_length, G3_t1); __ cmp(G4_length, G3_t1); __ br(Assembler::greaterUnsigned, false, Assembler::pn, slow_path); __ delayed()->nop(); // if we got here then the TLAB allocation failed, so try // refilling the TLAB or allocating directly from eden. Label retry_tlab, try_eden; __ tlab_refill(retry_tlab, try_eden, slow_path); // preserves G4_length and G5_klass __ bind(retry_tlab); // get the allocation size: (length << (layout_helper & 0x1F)) + header_size __ ld(klass_lh, G3_t1); __ sll(G4_length, G3_t1, G1_arr_size); __ srl(G3_t1, Klass::_lh_header_size_shift, G3_t1); __ and3(G3_t1, Klass::_lh_header_size_mask, G3_t1); __ add(G1_arr_size, G3_t1, G1_arr_size); __ add(G1_arr_size, MinObjAlignmentInBytesMask, G1_arr_size); // align up __ and3(G1_arr_size, ~MinObjAlignmentInBytesMask, G1_arr_size); __ tlab_allocate(O0_obj, G1_arr_size, 0, G3_t1, slow_path); // preserves G1_arr_size __ initialize_header(O0_obj, G5_klass, G4_length, G3_t1, O1_t2); __ ldub(klass_lh, G3_t1, klass_lh_header_size_offset); __ sub(G1_arr_size, G3_t1, O1_t2); // body length __ add(O0_obj, G3_t1, G3_t1); // body start __ initialize_body(G3_t1, O1_t2); __ verify_oop(O0_obj); __ retl(); __ delayed()->nop(); __ bind(try_eden); // get the allocation size: (length << (layout_helper & 0x1F)) + header_size __ ld(klass_lh, G3_t1); __ sll(G4_length, G3_t1, G1_arr_size); __ srl(G3_t1, Klass::_lh_header_size_shift, G3_t1); __ and3(G3_t1, Klass::_lh_header_size_mask, G3_t1); __ add(G1_arr_size, G3_t1, G1_arr_size); __ add(G1_arr_size, MinObjAlignmentInBytesMask, G1_arr_size); __ and3(G1_arr_size, ~MinObjAlignmentInBytesMask, G1_arr_size); __ eden_allocate(O0_obj, G1_arr_size, 0, G3_t1, O1_t2, slow_path); // preserves G1_arr_size __ initialize_header(O0_obj, G5_klass, G4_length, G3_t1, O1_t2); __ ldub(klass_lh, G3_t1, klass_lh_header_size_offset); __ sub(G1_arr_size, G3_t1, O1_t2); // body length __ add(O0_obj, G3_t1, G3_t1); // body start __ initialize_body(G3_t1, O1_t2); __ verify_oop(O0_obj); __ retl(); __ delayed()->nop(); __ bind(slow_path); } if (id == new_type_array_id) { oop_maps = generate_stub_call(sasm, I0, CAST_FROM_FN_PTR(address, new_type_array), G5_klass, G4_length); } else { oop_maps = generate_stub_call(sasm, I0, CAST_FROM_FN_PTR(address, new_object_array), G5_klass, G4_length); } // I0 -> O0: new array } break; case new_multi_array_id: { // O0: klass // O1: rank // O2: address of 1st dimension __ set_info("new_multi_array", dont_gc_arguments); oop_maps = generate_stub_call(sasm, I0, CAST_FROM_FN_PTR(address, new_multi_array), I0, I1, I2); // I0 -> O0: new multi array } break; case register_finalizer_id: { __ set_info("register_finalizer", dont_gc_arguments); // load the klass and check the has finalizer flag Label register_finalizer; Register t = O1; __ ld_ptr(O0, oopDesc::klass_offset_in_bytes(), t); __ ld(t, Klass::access_flags_offset_in_bytes() + sizeof(oopDesc), t); __ set(JVM_ACC_HAS_FINALIZER, G3); __ andcc(G3, t, G0); __ br(Assembler::notZero, false, Assembler::pt, register_finalizer); __ delayed()->nop(); // do a leaf return __ retl(); __ delayed()->nop(); __ bind(register_finalizer); OopMap* oop_map = save_live_registers(sasm); int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, SharedRuntime::register_finalizer), I0); oop_maps = new OopMapSet(); oop_maps->add_gc_map(call_offset, oop_map); // Now restore all the live registers restore_live_registers(sasm); __ ret(); __ delayed()->restore(); } break; case throw_range_check_failed_id: { __ set_info("range_check_failed", dont_gc_arguments); // arguments will be discarded // G4: index oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_range_check_exception), true); } break; case throw_index_exception_id: { __ set_info("index_range_check_failed", dont_gc_arguments); // arguments will be discarded // G4: index oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_index_exception), true); } break; case throw_div0_exception_id: { __ set_info("throw_div0_exception", dont_gc_arguments); oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_div0_exception), false); } break; case throw_null_pointer_exception_id: { __ set_info("throw_null_pointer_exception", dont_gc_arguments); oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_null_pointer_exception), false); } break; case handle_exception_id: { __ set_info("handle_exception", dont_gc_arguments); // make a frame and preserve the caller's caller-save registers oop_maps = new OopMapSet(); OopMap* oop_map = save_live_registers(sasm); __ mov(Oexception->after_save(), Oexception); __ mov(Oissuing_pc->after_save(), Oissuing_pc); generate_handle_exception(sasm, oop_maps, oop_map); } break; case unwind_exception_id: { // O0: exception // I7: address of call to this method __ set_info("unwind_exception", dont_gc_arguments); __ mov(Oexception, Oexception->after_save()); __ add(I7, frame::pc_return_offset, Oissuing_pc->after_save()); __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), Oissuing_pc->after_save()); __ verify_not_null_oop(Oexception->after_save()); __ jmp(O0, 0); __ delayed()->restore(); } break; case throw_array_store_exception_id: { __ set_info("throw_array_store_exception", dont_gc_arguments); oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_array_store_exception), false); } break; case throw_class_cast_exception_id: { // G4: object __ set_info("throw_class_cast_exception", dont_gc_arguments); oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_class_cast_exception), true); } break; case throw_incompatible_class_change_error_id: { __ set_info("throw_incompatible_class_cast_exception", dont_gc_arguments); oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_incompatible_class_change_error), false); } break; case slow_subtype_check_id: { // Support for uint StubRoutine::partial_subtype_check( Klass sub, Klass super ); // Arguments : // // ret : G3 // sub : G3, argument, destroyed // super: G1, argument, not changed // raddr: O7, blown by call Label miss; __ save_frame(0); // Blow no registers! __ check_klass_subtype_slow_path(G3, G1, L0, L1, L2, L4, NULL, &miss); __ mov(1, G3); __ ret(); // Result in G5 is 'true' __ delayed()->restore(); // free copy or add can go here __ bind(miss); __ mov(0, G3); __ ret(); // Result in G5 is 'false' __ delayed()->restore(); // free copy or add can go here } case monitorenter_nofpu_id: case monitorenter_id: { // G4: object // G5: lock address __ set_info("monitorenter", dont_gc_arguments); int save_fpu_registers = (id == monitorenter_id); // make a frame and preserve the caller's caller-save registers OopMap* oop_map = save_live_registers(sasm, save_fpu_registers); int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorenter), G4, G5); oop_maps = new OopMapSet(); oop_maps->add_gc_map(call_offset, oop_map); restore_live_registers(sasm, save_fpu_registers); __ ret(); __ delayed()->restore(); } break; case monitorexit_nofpu_id: case monitorexit_id: { // G4: lock address // note: really a leaf routine but must setup last java sp // => use call_RT for now (speed can be improved by // doing last java sp setup manually) __ set_info("monitorexit", dont_gc_arguments); int save_fpu_registers = (id == monitorexit_id); // make a frame and preserve the caller's caller-save registers OopMap* oop_map = save_live_registers(sasm, save_fpu_registers); int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorexit), G4); oop_maps = new OopMapSet(); oop_maps->add_gc_map(call_offset, oop_map); restore_live_registers(sasm, save_fpu_registers); __ ret(); __ delayed()->restore(); } break; case access_field_patching_id: { __ set_info("access_field_patching", dont_gc_arguments); oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, access_field_patching)); } break; case load_klass_patching_id: { __ set_info("load_klass_patching", dont_gc_arguments); oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_klass_patching)); } break; case jvmti_exception_throw_id: { // Oexception : exception __ set_info("jvmti_exception_throw", dont_gc_arguments); oop_maps = generate_stub_call(sasm, noreg, CAST_FROM_FN_PTR(address, Runtime1::post_jvmti_exception_throw), I0); } break; case dtrace_object_alloc_id: { // O0: object __ set_info("dtrace_object_alloc", dont_gc_arguments); // we can't gc here so skip the oopmap but make sure that all // the live registers get saved. save_live_registers(sasm); __ save_thread(L7_thread_cache); __ call(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc), relocInfo::runtime_call_type); __ delayed()->mov(I0, O0); __ restore_thread(L7_thread_cache); restore_live_registers(sasm); __ ret(); __ delayed()->restore(); } break; #ifndef SERIALGC case g1_pre_barrier_slow_id: { // G4: previous value of memory BarrierSet* bs = Universe::heap()->barrier_set(); if (bs->kind() != BarrierSet::G1SATBCTLogging) { __ save_frame(0); __ set((int)id, O1); __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), I0); __ should_not_reach_here(); break; } __ set_info("g1_pre_barrier_slow_id", dont_gc_arguments); Register pre_val = G4; Register tmp = G1_scratch; Register tmp2 = G3_scratch; Label refill, restart; bool with_frame = false; // I don't know if we can do with-frame. int satb_q_index_byte_offset = in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_index()); int satb_q_buf_byte_offset = in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_buf()); __ bind(restart); __ ld_ptr(G2_thread, satb_q_index_byte_offset, tmp); __ br_on_reg_cond(Assembler::rc_z, /*annul*/false, Assembler::pn, tmp, refill); // If the branch is taken, no harm in executing this in the delay slot. __ delayed()->ld_ptr(G2_thread, satb_q_buf_byte_offset, tmp2); __ sub(tmp, oopSize, tmp); __ st_ptr(pre_val, tmp2, tmp); // [_buf + index] := <address_of_card> // Use return-from-leaf __ retl(); __ delayed()->st_ptr(tmp, G2_thread, satb_q_index_byte_offset); __ bind(refill); __ save_frame(0); __ mov(pre_val, L0); __ mov(tmp, L1); __ mov(tmp2, L2); __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, SATBMarkQueueSet::handle_zero_index_for_thread), G2_thread); __ mov(L0, pre_val); __ mov(L1, tmp); __ mov(L2, tmp2); __ br(Assembler::always, /*annul*/false, Assembler::pt, restart); __ delayed()->restore(); } break; case g1_post_barrier_slow_id: { BarrierSet* bs = Universe::heap()->barrier_set(); if (bs->kind() != BarrierSet::G1SATBCTLogging) { __ save_frame(0); __ set((int)id, O1); __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), I0); __ should_not_reach_here(); break; } __ set_info("g1_post_barrier_slow_id", dont_gc_arguments); Register addr = G4; Register cardtable = G5; Register tmp = G1_scratch; Register tmp2 = G3_scratch; jbyte* byte_map_base = ((CardTableModRefBS*)bs)->byte_map_base; Label not_already_dirty, restart, refill; #ifdef _LP64 __ srlx(addr, CardTableModRefBS::card_shift, addr); #else __ srl(addr, CardTableModRefBS::card_shift, addr); #endif AddressLiteral rs(byte_map_base); __ set(rs, cardtable); // cardtable := <card table base> __ ldub(addr, cardtable, tmp); // tmp := [addr + cardtable] __ br_on_reg_cond(Assembler::rc_nz, /*annul*/false, Assembler::pt, tmp, not_already_dirty); // Get cardtable + tmp into a reg by itself -- useful in the take-the-branch // case, harmless if not. __ delayed()->add(addr, cardtable, tmp2); // We didn't take the branch, so we're already dirty: return. // Use return-from-leaf __ retl(); __ delayed()->nop(); // Not dirty. __ bind(not_already_dirty); // First, dirty it. __ stb(G0, tmp2, 0); // [cardPtr] := 0 (i.e., dirty). Register tmp3 = cardtable; Register tmp4 = tmp; // these registers are now dead addr = cardtable = tmp = noreg; int dirty_card_q_index_byte_offset = in_bytes(JavaThread::dirty_card_queue_offset() + PtrQueue::byte_offset_of_index()); int dirty_card_q_buf_byte_offset = in_bytes(JavaThread::dirty_card_queue_offset() + PtrQueue::byte_offset_of_buf()); __ bind(restart); __ ld_ptr(G2_thread, dirty_card_q_index_byte_offset, tmp3); __ br_on_reg_cond(Assembler::rc_z, /*annul*/false, Assembler::pn, tmp3, refill); // If the branch is taken, no harm in executing this in the delay slot. __ delayed()->ld_ptr(G2_thread, dirty_card_q_buf_byte_offset, tmp4); __ sub(tmp3, oopSize, tmp3); __ st_ptr(tmp2, tmp4, tmp3); // [_buf + index] := <address_of_card> // Use return-from-leaf __ retl(); __ delayed()->st_ptr(tmp3, G2_thread, dirty_card_q_index_byte_offset); __ bind(refill); __ save_frame(0); __ mov(tmp2, L0); __ mov(tmp3, L1); __ mov(tmp4, L2); __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, DirtyCardQueueSet::handle_zero_index_for_thread), G2_thread); __ mov(L0, tmp2); __ mov(L1, tmp3); __ mov(L2, tmp4); __ br(Assembler::always, /*annul*/false, Assembler::pt, restart); __ delayed()->restore(); } break; #endif // !SERIALGC default: { __ set_info("unimplemented entry", dont_gc_arguments); __ save_frame(0); __ set((int)id, O1); __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), O1); __ should_not_reach_here(); } break; } return oop_maps; }
void SlotLocation::MoveToSlot(MacroAssembler* masm, SlotLocation* loc) { // The accumulator is not live across a MoveInstr. __ mov(eax, ToOperand(this)); __ mov(ToOperand(loc), eax); }
static transfer_control_stub_type gen_transfer_control_stub() { static transfer_control_stub_type addr = NULL; if (addr) { return addr; } const int STUB_SIZE = 255; char * stub = (char *)malloc_fixed_code_for_jit(STUB_SIZE, DEFAULT_CODE_ALIGNMENT, CODE_BLOCK_HEAT_COLD, CAA_Allocate); char * ss = stub; #ifndef NDEBUG memset(stub, 0xcc /*int 3*/, STUB_SIZE); #endif // // ************* LOW LEVEL DEPENDENCY! *************** // This code sequence must be atomic. The "atomicity" effect is achieved by // changing the rsp at the very end of the sequence. // rdx holds the pointer to the stack iterator #if defined (PLATFORM_POSIX) // RDI holds 1st parameter on Linux ss = mov(ss, rdx_opnd, rdi_opnd); #else // RCX holds 1st parameter on Windows ss = mov(ss, rdx_opnd, rcx_opnd); #endif // Restore general registers ss = get_reg(ss, rbp_opnd, rdx_reg, CONTEXT_OFFSET(p_rbp), false); ss = get_reg(ss, rbx_opnd, rdx_reg, CONTEXT_OFFSET(p_rbx), true); ss = get_reg(ss, r12_opnd, rdx_reg, CONTEXT_OFFSET(p_r12), true); ss = get_reg(ss, r13_opnd, rdx_reg, CONTEXT_OFFSET(p_r13), true); ss = get_reg(ss, r14_opnd, rdx_reg, CONTEXT_OFFSET(p_r14), true); ss = get_reg(ss, r15_opnd, rdx_reg, CONTEXT_OFFSET(p_r15), true); ss = get_reg(ss, rsi_opnd, rdx_reg, CONTEXT_OFFSET(p_rsi), true); ss = get_reg(ss, rdi_opnd, rdx_reg, CONTEXT_OFFSET(p_rdi), true); ss = get_reg(ss, r8_opnd, rdx_reg, CONTEXT_OFFSET(p_r8), true); ss = get_reg(ss, r9_opnd, rdx_reg, CONTEXT_OFFSET(p_r9), true); ss = get_reg(ss, r10_opnd, rdx_reg, CONTEXT_OFFSET(p_r10), true); ss = get_reg(ss, r11_opnd, rdx_reg, CONTEXT_OFFSET(p_r11), true); // Get the new RSP M_Base_Opnd saved_rsp(rdx_reg, CONTEXT_OFFSET(rsp)); ss = mov(ss, rax_opnd, saved_rsp); // Store it over return address for future use ss = mov(ss, M_Base_Opnd(rsp_reg, 0), rax_opnd); // Get the new RIP ss = get_reg(ss, rcx_opnd, rdx_reg, CONTEXT_OFFSET(p_rip), false); // Store RIP to [<new RSP> - 136] to preserve 128 bytes under RSP // which are 'reserved' on Linux ss = mov(ss, M_Base_Opnd(rax_reg, -136), rcx_opnd); ss = get_reg(ss, rax_opnd, rdx_reg, CONTEXT_OFFSET(p_rax), true); // Restore processor flags ss = movzx(ss, rcx_opnd, M_Base_Opnd(rdx_reg, CONTEXT_OFFSET(eflags)), size_16); ss = test(ss, rcx_opnd, rcx_opnd); ss = branch8(ss, Condition_Z, Imm_Opnd(size_8, 0)); char* patch_offset = ((char*)ss) - 1; // Store location for jump patch *ss++ = (char)0x9C; // PUSHFQ M_Base_Opnd sflags(rsp_reg, 0); ss = alu(ss, and_opc, sflags, Imm_Opnd(size_32,FLG_CLEAR_MASK), size_32); ss = alu(ss, and_opc, rcx_opnd, Imm_Opnd(size_32,FLG_SET_MASK), size_32); ss = alu(ss, or_opc, sflags, rcx_opnd, size_32); *ss++ = (char)0x9D; // POPFQ // Patch conditional jump POINTER_SIZE_SINT offset = (POINTER_SIZE_SINT)ss - (POINTER_SIZE_SINT)patch_offset - 1; *patch_offset = (char)offset; ss = get_reg(ss, rcx_opnd, rdx_reg, CONTEXT_OFFSET(p_rcx), true, true); ss = get_reg(ss, rdx_opnd, rdx_reg, CONTEXT_OFFSET(p_rdx), true, true); // Setup stack pointer to previously saved value ss = mov(ss, rsp_opnd, M_Base_Opnd(rsp_reg, 0)); // Jump to address stored to [<new RSP> - 136] ss = jump(ss, M_Base_Opnd(rsp_reg, -136)); addr = (transfer_control_stub_type)stub; assert(ss-stub <= STUB_SIZE); /* The following code will be generated: mov rdx,rcx mov rbp,qword ptr [rdx+10h] mov rbp,qword ptr [rbp] mov rbx,qword ptr [rdx+20h] test rbx,rbx je __label1__ mov rbx,qword ptr [rbx] __label1__ ; .... The same for r12,r13,r14,r15,rsi,rdi,r8,r9,r10 mov r11,qword ptr [rdx+88h] test r11,r11 je __label11__ mov r11,qword ptr [r11] __label11__ mov rax,qword ptr [rdx+8] mov qword ptr [rsp],rax mov rcx,qword ptr [rdx+18h] mov rcx,qword ptr [rcx] mov qword ptr [rax-88h],rcx mov rax,qword ptr [rdx+48h] test rax,rax je __label12__ mov rax,qword ptr [rax] __label12__ movzx rcx,word ptr [rdx+90h] test rcx,rcx je __label13__ pushfq and dword ptr [rsp], 0x003F7202 and ecx, 0x00000CD5 or dword ptr [esp], ecx popfq __label13__ mov rcx,qword ptr [rdx+50h] pushfq test rcx,rcx je __label14__ mov rcx,qword ptr [rcx] __label14__ popfq mov rdx,qword ptr [rdx+58h] pushfq test rdx,rdx je __label15__ mov rdx,qword ptr [rdx] __label15__ popfq mov rsp,qword ptr [rsp] jmp qword ptr [rsp-88h] */ DUMP_STUB(stub, "getaddress__transfer_control", ss-stub); return addr; }
address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) { const char *name; switch (type) { case T_FLOAT: name = "jni_fast_GetFloatField"; break; case T_DOUBLE: name = "jni_fast_GetDoubleField"; break; default: ShouldNotReachHere(); } ResourceMark rm; BufferBlob* b = BufferBlob::create(name, BUFFER_SIZE*wordSize); address fast_entry = b->instructions_begin(); CodeBuffer cbuf(fast_entry, b->instructions_size()); MacroAssembler* masm = new MacroAssembler(&cbuf); Label slow_with_pop, slow; // stack layout: offset from rsp (in words): // return pc 0 // jni env 1 // obj 2 // jfieldID 3 ExternalAddress counter(SafepointSynchronize::safepoint_counter_addr()); __ mov32 (rcx, counter); __ testb (rcx, 1); __ jcc (Assembler::notZero, slow); if (os::is_MP()) { __ mov(rax, rcx); __ andptr(rax, 1); // rax, must end up 0 __ movptr(rdx, Address(rsp, rax, Address::times_1, 2*wordSize)); // obj, notice rax, is 0. // rdx is data dependent on rcx. } else { __ movptr(rdx, Address(rsp, 2*wordSize)); // obj } __ movptr(rax, Address(rsp, 3*wordSize)); // jfieldID __ movptr(rdx, Address(rdx, 0)); // *obj __ shrptr(rax, 2); // offset assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); speculative_load_pclist[count] = __ pc(); switch (type) { #ifndef _LP64 case T_FLOAT: __ fld_s (Address(rdx, rax, Address::times_1)); break; case T_DOUBLE: __ fld_d (Address(rdx, rax, Address::times_1)); break; #else case T_FLOAT: __ movflt (xmm0, Address(robj, roffset, Address::times_1)); break; case T_DOUBLE: __ movdbl (xmm0, Address(robj, roffset, Address::times_1)); break; #endif // _LP64 default: ShouldNotReachHere(); } Address ca1; if (os::is_MP()) { __ fst_s (Address(rsp, -4)); __ lea(rdx, counter); __ movl (rax, Address(rsp, -4)); // garbage hi-order bits on 64bit are harmless. __ xorptr(rdx, rax); __ xorptr(rdx, rax); __ cmp32(rcx, Address(rdx, 0)); // rax, ^ counter_addr ^ rax, = address // ca1 is data dependent on the field // access. } else { __ cmp32(rcx, counter); } __ jcc (Assembler::notEqual, slow_with_pop); #ifndef _WINDOWS __ ret (0); #else // __stdcall calling convention __ ret (3*wordSize); #endif __ bind (slow_with_pop); // invalid load. pop FPU stack. __ fstp_d (0); slowcase_entry_pclist[count++] = __ pc(); __ bind (slow); address slow_case_addr; switch (type) { case T_FLOAT: slow_case_addr = jni_GetFloatField_addr(); break; case T_DOUBLE: slow_case_addr = jni_GetDoubleField_addr(); break; default: ShouldNotReachHere(); } // tail call __ jump (ExternalAddress(slow_case_addr)); __ flush (); #ifndef _WINDOWS return fast_entry; #else switch (type) { case T_FLOAT: jni_fast_GetFloatField_fp = (GetFloatField_t)fast_entry; break; case T_DOUBLE: jni_fast_GetDoubleField_fp = (GetDoubleField_t)fast_entry; } return os::win32::fast_jni_accessor_wrapper(type); #endif }
void m_mgrhand_for_sched::_mov(map_type& lhs, map_type& rhs, const id_type id) { scoped_lock _lck(obj()->_mlock); mov(lhs, rhs, id); }
address TemplateInterpreterGenerator::generate_slow_signature_handler() { address entry = __ pc(); // rbx: method // r14: pointer to locals // c_rarg3: first stack arg - wordSize __ mov(c_rarg3, rsp); // adjust rsp __ subptr(rsp, 14 * wordSize); __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::slow_signature_handler), rbx, r14, c_rarg3); // rax: result handler // Stack layout: // rsp: 5 integer args (if static first is unused) // 1 float/double identifiers // 8 double args // return address // stack args // garbage // expression stack bottom // bcp (NULL) // ... // Do FP first so we can use c_rarg3 as temp __ movl(c_rarg3, Address(rsp, 5 * wordSize)); // float/double identifiers for (int i = 0; i < Argument::n_float_register_parameters_c; i++) { const XMMRegister r = as_XMMRegister(i); Label d, done; __ testl(c_rarg3, 1 << i); __ jcc(Assembler::notZero, d); __ movflt(r, Address(rsp, (6 + i) * wordSize)); __ jmp(done); __ bind(d); __ movdbl(r, Address(rsp, (6 + i) * wordSize)); __ bind(done); } // Now handle integrals. Only do c_rarg1 if not static. __ movl(c_rarg3, Address(rbx, Method::access_flags_offset())); __ testl(c_rarg3, JVM_ACC_STATIC); __ cmovptr(Assembler::zero, c_rarg1, Address(rsp, 0)); __ movptr(c_rarg2, Address(rsp, wordSize)); __ movptr(c_rarg3, Address(rsp, 2 * wordSize)); __ movptr(c_rarg4, Address(rsp, 3 * wordSize)); __ movptr(c_rarg5, Address(rsp, 4 * wordSize)); // restore rsp __ addptr(rsp, 14 * wordSize); __ ret(0); return entry; }
void GSDrawScanlineCodeGenerator::SampleTexture() { if(!m_sel.fb || m_sel.tfx == TFX_NONE) { return; } mov(rbx, ptr[r12 + offsetof(GSScanlineGlobalData, tex)]); // ebx = tex if(!m_sel.fst) { vrcpps(xmm0, xmm12); vmulps(xmm4, xmm10, xmm0); vmulps(xmm5, xmm11, xmm0); vcvttps2dq(xmm4, xmm4); vcvttps2dq(xmm5, xmm5); if(m_sel.ltf) { // u -= 0x8000; // v -= 0x8000; mov(eax, 0x8000); vmovd(xmm0, eax); vpshufd(xmm0, xmm0, _MM_SHUFFLE(0, 0, 0, 0)); vpsubd(xmm4, xmm0); vpsubd(xmm5, xmm0); } } else { vmovdqa(xmm4, xmm10); vmovdqa(xmm5, xmm11); } if(m_sel.ltf) { // GSVector4i uf = u.xxzzlh().srl16(1); vpshuflw(xmm6, xmm4, _MM_SHUFFLE(2, 2, 0, 0)); vpshufhw(xmm6, xmm6, _MM_SHUFFLE(2, 2, 0, 0)); vpsrlw(xmm6, 1); if(!m_sel.sprite) { // GSVector4i vf = v.xxzzlh().srl16(1); vpshuflw(xmm7, xmm5, _MM_SHUFFLE(2, 2, 0, 0)); vpshufhw(xmm7, xmm7, _MM_SHUFFLE(2, 2, 0, 0)); vpsrlw(xmm7, 1); } } // GSVector4i uv0 = u.sra32(16).ps32(v.sra32(16)); vpsrad(xmm4, 16); vpsrad(xmm5, 16); vpackssdw(xmm4, xmm5); if(m_sel.ltf) { // GSVector4i uv1 = uv0.add16(GSVector4i::x0001()); vpcmpeqd(xmm0, xmm0); vpsrlw(xmm0, 15); vpaddw(xmm5, xmm4, xmm0); // uv0 = Wrap(uv0); // uv1 = Wrap(uv1); Wrap(xmm4, xmm5); } else { // uv0 = Wrap(uv0); Wrap(xmm4); } // xmm4 = uv0 // xmm5 = uv1 (ltf) // xmm6 = uf // xmm7 = vf // GSVector4i x0 = uv0.upl16(); // GSVector4i y0 = uv0.uph16() << tw; vpxor(xmm0, xmm0); vpunpcklwd(xmm2, xmm4, xmm0); vpunpckhwd(xmm3, xmm4, xmm0); vpslld(xmm3, m_sel.tw + 3); // xmm0 = 0 // xmm2 = x0 // xmm3 = y0 // xmm5 = uv1 (ltf) // xmm6 = uf // xmm7 = vf if(m_sel.ltf) { // GSVector4i x1 = uv1.upl16(); // GSVector4i y1 = uv1.uph16() << tw; vpunpcklwd(xmm4, xmm5, xmm0); vpunpckhwd(xmm5, xmm5, xmm0); vpslld(xmm5, m_sel.tw + 3); // xmm2 = x0 // xmm3 = y0 // xmm4 = x1 // xmm5 = y1 // xmm6 = uf // xmm7 = vf // GSVector4i addr00 = y0 + x0; // GSVector4i addr01 = y0 + x1; // GSVector4i addr10 = y1 + x0; // GSVector4i addr11 = y1 + x1; vpaddd(xmm0, xmm3, xmm2); vpaddd(xmm1, xmm3, xmm4); vpaddd(xmm2, xmm5, xmm2); vpaddd(xmm3, xmm5, xmm4); // xmm0 = addr00 // xmm1 = addr01 // xmm2 = addr10 // xmm3 = addr11 // xmm6 = uf // xmm7 = vf // c00 = addr00.gather32_32((const uint32/uint8*)tex[, clut]); // c01 = addr01.gather32_32((const uint32/uint8*)tex[, clut]); // c10 = addr10.gather32_32((const uint32/uint8*)tex[, clut]); // c11 = addr11.gather32_32((const uint32/uint8*)tex[, clut]); ReadTexel(4, 0); // xmm0 = c00 // xmm1 = c01 // xmm2 = c10 // xmm3 = c11 // xmm6 = uf // xmm7 = vf // GSVector4i rb00 = c00 & mask; // GSVector4i ga00 = (c00 >> 8) & mask; vpsllw(xmm4, xmm0, 8); vpsrlw(xmm4, 8); vpsrlw(xmm5, xmm0, 8); // GSVector4i rb01 = c01 & mask; // GSVector4i ga01 = (c01 >> 8) & mask; vpsllw(xmm0, xmm1, 8); vpsrlw(xmm0, 8); vpsrlw(xmm1, 8); // xmm0 = rb01 // xmm1 = ga01 // xmm2 = c10 // xmm3 = c11 // xmm4 = rb00 // xmm5 = ga00 // xmm6 = uf // xmm7 = vf // rb00 = rb00.lerp16<0>(rb01, uf); // ga00 = ga00.lerp16<0>(ga01, uf); lerp16(xmm0, xmm4, xmm6, 0); lerp16(xmm1, xmm5, xmm6, 0); // xmm0 = rb00 // xmm1 = ga00 // xmm2 = c10 // xmm3 = c11 // xmm6 = uf // xmm7 = vf // GSVector4i rb10 = c10 & mask; // GSVector4i ga10 = (c10 >> 8) & mask; vpsrlw(xmm5, xmm2, 8); vpsllw(xmm2, 8); vpsrlw(xmm4, xmm2, 8); // GSVector4i rb11 = c11 & mask; // GSVector4i ga11 = (c11 >> 8) & mask; vpsrlw(xmm2, xmm3, 8); vpsllw(xmm3, 8); vpsrlw(xmm3, 8); // xmm0 = rb00 // xmm1 = ga00 // xmm2 = rb11 // xmm3 = ga11 // xmm4 = rb10 // xmm5 = ga10 // xmm6 = uf // xmm7 = vf // rb10 = rb10.lerp16<0>(rb11, uf); // ga10 = ga10.lerp16<0>(ga11, uf); lerp16(xmm2, xmm4, xmm6, 0); lerp16(xmm3, xmm5, xmm6, 0); // xmm0 = rb00 // xmm1 = ga00 // xmm2 = rb10 // xmm3 = ga10 // xmm7 = vf // rb00 = rb00.lerp16<0>(rb10, vf); // ga00 = ga00.lerp16<0>(ga10, vf); lerp16(xmm2, xmm0, xmm7, 0); lerp16(xmm3, xmm1, xmm7, 0); } else { // GSVector4i addr00 = y0 + x0; vpaddd(xmm3, xmm2); // c00 = addr00.gather32_32((const uint32/uint8*)tex[, clut]); ReadTexel(1, 0); // GSVector4i mask = GSVector4i::x00ff(); // c[0] = c00 & mask; // c[1] = (c00 >> 8) & mask; vpsrlw(xmm3, xmm2, 8); vpsllw(xmm2, 8); vpsrlw(xmm2, 8); } // xmm2 = rb // xmm3 = ga }