address generate_d2i_wrapper( address fcn ) { StubCodeMark mark(this, "StubRoutines", "d2i_wrapper"); address start = __ pc(); // Capture info about frame layout enum layout { FPUState_off = 0, ebp_off = FPUStateSizeInWords, edi_off, esi_off, ecx_off, ebx_off, saved_argument_off, saved_argument_off2, // 2nd half of double framesize }; assert(FPUStateSizeInWords == 27, "update stack layout"); // Save outgoing argument to stack across push_FPU_state() __ subl(esp, wordSize * 2); __ fstp_d(Address(esp)); // Save CPU & FPU state __ pushl(ebx); __ pushl(ecx); __ pushl(esi); __ pushl(edi); __ pushl(ebp); __ push_FPU_state(); // push_FPU_state() resets the FP top of stack // Load original double into FP top of stack __ fld_d(Address(esp, saved_argument_off * wordSize)); // Store double into stack as outgoing argument __ subl(esp, wordSize*2); __ fst_d(Address(esp)); // Prepare FPU for doing math in C-land __ empty_FPU_stack(); // Call the C code to massage the double. Result in EAX __ call_VM_leaf( fcn, 2 ); // Restore CPU & FPU state __ pop_FPU_state(); __ popl(ebp); __ popl(edi); __ popl(esi); __ popl(ecx); __ popl(ebx); __ addl(esp, wordSize * 2); __ ret(0); return start; }
OSRAdapter* SharedRuntime::generate_osr_blob(int frame_size) { ResourceMark rm; // setup code generation tools CodeBuffer* cb = new CodeBuffer(128, 128, 0, 0, 0, false); MacroAssembler* masm = new MacroAssembler(cb); OopMapSet *oop_maps = new OopMapSet(); OopMap* map = new OopMap(frame_size, 0 ); OopMap* map2 = new OopMap(frame_size, 0 ); #ifdef COMPILER2 // Create oopmap for osr adapter. All it contains is where to find the // link offset (ebp) on windows. int link_offset = ((frame_size - frame::sender_sp_offset) + frame::link_offset); map->set_callee_saved(OptoReg::Name(SharedInfo::stack0 + link_offset), frame_size, 0, OptoReg::Name(EBP_num)); map2->set_callee_saved(OptoReg::Name(SharedInfo::stack0 + link_offset), frame_size, 0, OptoReg::Name(EBP_num)); #endif oop_maps->add_gc_map(0, true, map); // Empty all except FPR0 in case of float/double returns __ ffree(0); int returning_fp_entry_offset = __ offset(); oop_maps->add_gc_map(returning_fp_entry_offset, true, map2); for (int i = 1; i<8; i++ ) __ ffree(i); __ movl(ecx, Address(ebp, frame::interpreter_frame_sender_sp_offset * wordSize)); // get sender sp __ leave(); // remove frame anchor __ popl(esi); // get return address __ movl(esp, ecx); // set sp to sender sp __ jmp(esi); __ flush(); return OSRAdapter::new_osr_adapter(cb, oop_maps, frame_size, returning_fp_entry_offset); }
address generate_forward_exception() { StubCodeMark mark(this, "StubRoutines", "forward exception"); address start = __ pc(); // Upon entry, the sp points to the return address returning into Java // (interpreted or compiled) code; i.e., the return address becomes the // throwing pc. // // Arguments pushed before the runtime call are still on the stack but // the exception handler will reset the stack pointer -> ignore them. // A potential result in registers can be ignored as well. #ifdef ASSERT // make sure this code is only executed if there is a pending exception { Label L; __ get_thread(ecx); __ cmpl(Address(ecx, Thread::pending_exception_offset()), (int)NULL); __ jcc(Assembler::notEqual, L); __ stop("StubRoutines::forward exception: no pending exception (1)"); __ bind(L); } #endif // compute exception handler into ebx __ movl(eax, Address(esp)); __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), eax); __ movl(ebx, eax); // setup eax & edx, remove return address & clear pending exception __ get_thread(ecx); __ popl(edx); __ movl(eax, Address(ecx, Thread::pending_exception_offset())); __ movl(Address(ecx, Thread::pending_exception_offset()), (int)NULL); #ifdef ASSERT // make sure exception is set { Label L; __ testl(eax, eax); __ jcc(Assembler::notEqual, L); __ stop("StubRoutines::forward exception: no pending exception (2)"); __ bind(L); } #endif // continue at exception handler (return address removed) // eax: exception // ebx: exception handler // edx: throwing pc __ verify_oop(eax); __ jmp(ebx); return start; }
void InterpreterStubs::generate_current_thread_to_primordial() { entry("current_thread_to_primordial"); // We're never going to return to this thread, so it doesn't matter if // it doesn't look like a stopped Java thread anymore. // pushl(ebp); // get_thread(ecx); // movl(Address(ecx, Constant(Thread::stack_pointer_offset())), esp); movl(esp, Address(Constant("_primordial_sp"))); popl(ebp); popal(); ret(); entry_end(); // current_thread_to_primordial }
address generate_get_previous_fp() { StubCodeMark mark(this, "StubRoutines", "get_previous_fp"); const Address old_fp (ebp, 0); const Address older_fp (eax, 0); address start = __ pc(); __ enter(); __ movl(eax, old_fp); // callers fp __ movl(eax, older_fp); // the frame for ps() __ popl(ebp); __ ret(0); return start; }
address generate_atomic_xchg() { StubCodeMark mark(this, "StubRoutines", "atomic_xchg"); address start = __ pc(); __ pushl(edx); Address exchange(esp, 2 * wordSize); Address dest_addr(esp, 3 * wordSize); __ movl(eax, exchange); __ movl(edx, dest_addr); __ xchg(eax, Address(edx, 0)); __ popl(edx); __ ret(0); return start; }
void InterpreterStubs::generate_primordial_to_current_thread() { entry("primordial_to_current_thread"); pushal(); pushl(ebp); movl(Address(Constant("_primordial_sp")), esp); get_thread(ecx); movl(esp, Address(ecx, Constant(Thread::stack_pointer_offset()))); popl(ebp); ret(); entry_end(); // primordial_to_current_thread entry("start_lightweight_thread_asm"); // Should never reach here on x86 int3(); entry_end(); // start_lightweight_thread_asm }
address generate_call_stub(address& return_address) { StubCodeMark mark(this, "StubRoutines", "call_stub"); address start = __ pc(); // stub code parameters / addresses assert(frame::entry_frame_call_wrapper_offset == 2, "adjust this code"); bool sse_save = false; const Address esp_after_call(ebp, -4 * wordSize); // same as in generate_catch_exception()! const Address mxcsr_save (ebp, -4 * wordSize); const Address result (ebp, 3 * wordSize); const Address result_type (ebp, 4 * wordSize); const Address method (ebp, 5 * wordSize); const Address entry_point (ebp, 6 * wordSize); const Address parameters (ebp, 7 * wordSize); const Address parameter_size(ebp, 8 * wordSize); const Address thread (ebp, 9 * wordSize); // same as in generate_catch_exception()! #ifdef COMPILER2 sse_save = VM_Version::supports_sse(); #endif // stub code __ enter(); // save edi, esi, & ebx, according to C calling conventions __ pushl(edi); __ pushl(esi); __ pushl(ebx); __ subl(esp, wordSize); // space for %mxcsr save // save and initialize %mxcsr if (sse_save) { __ stmxcsr(mxcsr_save); __ ldmxcsr(Address((int) StubRoutines::addr_mxcsr_std(), relocInfo::none)); } #ifdef ASSERT // make sure we have no pending exceptions { Label L; __ movl(ecx, thread); __ cmpl(Address(ecx, Thread::pending_exception_offset()), (int)NULL); __ jcc(Assembler::equal, L); __ stop("StubRoutines::call_stub: entered with pending exception"); __ bind(L); } #endif // pass parameters if any Label parameters_done; __ movl(ecx, parameter_size); // parameter counter __ testl(ecx, ecx); __ jcc(Assembler::zero, parameters_done); // parameter passing loop Label loop; __ movl(edx, parameters); // parameter pointer __ movl(esi, ecx); // parameter counter is in esi now __ movl(ecx, Address(edx)); // get first parameter in case it is a receiver __ bind(loop); __ movl(eax, Address(edx)); // get parameter __ addl(edx, wordSize); // advance to next parameter __ decl(esi); // decrement counter __ pushl(eax); // pass parameter __ jcc(Assembler::notZero, loop); // call Java function __ bind(parameters_done); __ movl(ebx, method); // get methodOop __ movl(esi, entry_point); // get entry_point __ call(esi, relocInfo::none); return_address = __ pc(); // store result depending on type // (everything that is not T_LONG, T_FLOAT or T_DOUBLE is treated as T_INT) __ movl(edi, result); Label is_long, is_float, is_double, exit; __ movl(esi, result_type); __ cmpl(esi, T_LONG); __ jcc(Assembler::equal, is_long); __ cmpl(esi, T_FLOAT); __ jcc(Assembler::equal, is_float); __ cmpl(esi, T_DOUBLE); __ jcc(Assembler::equal, is_double); // handle T_INT case __ movl(Address(edi), eax); __ bind(exit); // pop parameters __ movl(ecx, parameter_size); __ leal(esp, Address(esp, ecx, Address::times_4)); // check if parameters have been popped correctly #ifdef ASSERT Label esp_wrong; __ leal(edi, esp_after_call); __ cmpl(esp, edi); __ jcc(Assembler::notEqual, esp_wrong); #endif // restore %mxcsr if (sse_save) { __ ldmxcsr(mxcsr_save); } // restore edi & esi __ addl(esp, wordSize); // remove %mxcsr save area __ popl(ebx); __ popl(esi); __ popl(edi); // return __ popl(ebp); __ ret(0); // handle return types different from T_INT __ bind(is_long); __ movl(Address(edi, 0 * wordSize), eax); __ movl(Address(edi, 1 * wordSize), edx); __ jmp(exit); __ bind(is_float); __ fstp_s(Address(edi)); __ jmp(exit); __ bind(is_double); __ fstp_d(Address(edi)); __ jmp(exit); #ifdef ASSERT // stack pointer misadjusted __ bind(esp_wrong); __ stop("esp wrong after Java call"); #endif return start; }
address generate_verify_oop() { StubCodeMark mark(this, "StubRoutines", "verify_oop"); address start = __ pc(); // Incoming arguments on stack after saving eax: // // [tos ]: saved edx // [tos + 1]: saved EFLAGS // [tos + 2]: return address // [tos + 3]: char* error message // [tos + 4]: oop object to verify // [tos + 5]: saved eax - saved by caller and bashed Label exit, error; __ pushfd(); __ incl(Address((int)StubRoutines::verify_oop_count_addr(), relocInfo::none)); __ pushl(edx); // save edx // make sure object is 'reasonable' __ movl(eax, Address(esp, 4 * wordSize)); // get object __ testl(eax, eax); __ jcc(Assembler::zero, exit); // if obj is NULL it is ok // Check if the oop is in the right area of memory const int oop_mask = Universe::verify_oop_mask(); const int oop_bits = Universe::verify_oop_bits(); __ movl(edx, eax); __ andl(edx, oop_mask); __ cmpl(edx, oop_bits); __ jcc(Assembler::notZero, error); // make sure klass is 'reasonable' __ movl(eax, Address(eax, oopDesc::klass_offset_in_bytes())); // get klass __ testl(eax, eax); __ jcc(Assembler::zero, error); // if klass is NULL it is broken // Check if the klass is in the right area of memory const int klass_mask = Universe::verify_klass_mask(); const int klass_bits = Universe::verify_klass_bits(); __ movl(edx, eax); __ andl(edx, klass_mask); __ cmpl(edx, klass_bits); __ jcc(Assembler::notZero, error); // make sure klass' klass is 'reasonable' __ movl(eax, Address(eax, oopDesc::klass_offset_in_bytes())); // get klass' klass __ testl(eax, eax); __ jcc(Assembler::zero, error); // if klass' klass is NULL it is broken __ movl(edx, eax); __ andl(edx, klass_mask); __ cmpl(edx, klass_bits); __ jcc(Assembler::notZero, error); // if klass not in right area // of memory it is broken too. // return if everything seems ok __ bind(exit); __ movl(eax, Address(esp, 5 * wordSize)); // get saved eax back __ popl(edx); // restore edx __ popfd(); // restore EFLAGS __ ret(3 * wordSize); // pop arguments // handle errors __ bind(error); __ movl(eax, Address(esp, 5 * wordSize)); // get saved eax back __ popl(edx); // get saved edx back __ popfd(); // get saved EFLAGS off stack -- will be ignored __ pushad(); // push registers (eip = return address & msg are already pushed) __ call(CAST_FROM_FN_PTR(address, MacroAssembler::debug), relocInfo::runtime_call_type); __ popad(); __ ret(3 * wordSize); // pop arguments return start; }
void handle_v86_fault( Virtual86Regs_s * regs, uint32 nErrorCode ) { unsigned char *csp, *ssp; unsigned long ip, sp; int nInst; // if ( 0xffff == (regs->eip & 0xffff) && 0xffff == regs->cs ) { // return_to_32bit( regs, 0 ); // return; // } csp = ( unsigned char * )( regs->cs << 4 ); ssp = ( unsigned char * )( regs->ss << 4 ); sp = regs->esp & 0xffff; ip = regs->eip & 0xffff; nInst = popb( csp, ip ); switch ( nInst ) { /* Operand size override */ case 0x66: printk( "WARNING : 32 bit code run in v86 mode! Flags are not handled properly!\n" ); nInst = popb( csp, ip ); switch ( nInst ) { /* pushfd */ case 0x9c: regs->esp = ( regs->esp - 4 ) & 0xffff; regs->eip = ( regs->eip + 2 ) & 0xffff; pushl( ssp, sp, regs->eflags ); return; /* popfd */ case 0x9d: regs->esp = ( regs->esp + 4 ) & 0xffff; regs->eip = ( regs->eip + 2 ) & 0xffff; regs->eflags = popl( ssp, sp ); return; /* iretd */ case 0xcf: regs->esp = ( regs->esp + 12 ) & 0xffff; regs->eip = ( uint16 )( popl( ssp, sp ) & 0xffff ); regs->cs = ( uint16 )popl( ssp, sp ); return; /* need this to avoid a fallthrough */ default: printk( "ERROR : unknown v86 32 bit instruction %x\n", nInst ); return_to_32bit( regs, -EFAULT ); } /* pushf */ case 0x9c: regs->esp = ( regs->esp - 2 ) & 0xffff; regs->eip = ( regs->eip + 1 ) & 0xffff; pushw( ssp, sp, regs->eflags & 0xffff ); return; /* popf */ case 0x9d: regs->esp = ( regs->esp + 2 ) & 0xffff; regs->eip = ( regs->eip + 1 ) & 0xffff; regs->eflags = ( regs->eflags & 0xffff0000 ) | ( popw( ssp, sp ) & 0xffff ); return; /* int xx */ case 0xcd: { int intno = popb( csp, ip ); regs->eip = ( regs->eip + 2 ) & 0xffff; do_int( regs, intno, ssp, sp ); return; } /* iret */ case 0xcf: regs->esp = ( regs->esp + 6 ) & 0xffff; regs->eip = popw( ssp, sp ) & 0xffff; regs->cs = popw( ssp, sp ); regs->eflags = ( regs->eflags & 0xffff0000 ) | ( popw( ssp, sp ) & 0xffff ); if ( 0xffff == ( regs->eip & 0xffff ) && 0xffff == regs->cs ) { return_to_32bit( regs, 0 ); } return; /* cli */ case 0xfa: regs->eip = ( regs->eip + 1 ) & 0xffff; regs->eflags &= ~EFLG_IF; return; /* sti */ case 0xfb: /* The interrupts should actually be restored after the NEXT instruction! * Hope this works. As long as no DOS/BIOS code swaps the stack, * nothing bad should happen. */ regs->eip = ( regs->eip + 1 ) & 0xffff; regs->eflags |= EFLG_IF; return; default: printk( "ERROR : unknown v86 16 bit instruction %x\n", nInst ); return_to_32bit( regs, -EFAULT ); } }
void NativeGenerator::generate_native_system_entries() { comment_section("Native entry points for system functions"); rom_linkable_entry("native_jvm_unchecked_byte_arraycopy_entry"); jmp(Constant("native_system_arraycopy_entry")); rom_linkable_entry_end(); rom_linkable_entry("native_jvm_unchecked_char_arraycopy_entry"); jmp(Constant("native_system_arraycopy_entry")); rom_linkable_entry_end(); rom_linkable_entry("native_jvm_unchecked_int_arraycopy_entry"); jmp(Constant("native_system_arraycopy_entry")); rom_linkable_entry_end(); rom_linkable_entry("native_jvm_unchecked_long_arraycopy_entry"); jmp(Constant("native_system_arraycopy_entry")); rom_linkable_entry_end(); rom_linkable_entry("native_jvm_unchecked_obj_arraycopy_entry"); jmp(Constant("native_system_arraycopy_entry")); rom_linkable_entry_end(); rom_linkable_entry("native_system_arraycopy_entry"); wtk_profile_quick_call(/* param_size*/ 5); Label bailout, cont, try_2_byte, try_4_byte, try_8_byte, do_4_byte; // public static native void arraycopy(Object src, int src_position, // Object dst, int dst_position, // int length); comment("preserve method"); pushl(ebx); // 8 is for the preserved method and the return address int length_offset = JavaFrame::arg_offset_from_sp(0) + 8, dst_pos_offset = JavaFrame::arg_offset_from_sp(1) + 8, dst_offset = JavaFrame::arg_offset_from_sp(2) + 8, src_pos_offset = JavaFrame::arg_offset_from_sp(3) + 8, src_offset = JavaFrame::arg_offset_from_sp(4) + 8; comment("load arguments to registers"); movl(ecx, Address(esp, Constant(length_offset))); movl(edi, Address(esp, Constant(dst_pos_offset))); movl(edx, Address(esp, Constant(dst_offset))); movl(esi, Address(esp, Constant(src_pos_offset))); movl(eax, Address(esp, Constant(src_offset))); // eax = src // ebx = tmp register // edx = dst // ecx = length // esi = src_pos // edi = dst_pos comment("if (src == NULL) goto bailout;"); testl( eax, eax ); jcc(zero, Constant(bailout)); comment("if (dst == NULL) goto bailout;"); testl( edx, edx ); jcc(zero, Constant(bailout)); comment("if (length < 0 || src_pos < 0 || dst_pos < 0) goto bailout;"); movl(ebx, ecx); orl(ebx, esi); orl(ebx, edi); jcc(negative, Constant(bailout)); comment("if ((unsigned int) dst.length < (unsigned int) dst_pos + (unsigned int) length) goto bailout;"); movl(ebx, ecx); addl(ebx, edi); cmpl(Address(edx, Constant(Array::length_offset())), ebx); jcc(below, Constant(bailout)); comment("if ((unsigned int) src.length < (unsigned int) src_pos + (unsigned int) length) goto bailout;"); movl(ebx, ecx); addl(ebx, esi); cmpl(Address(eax, Constant(Array::length_offset())), ebx); jcc(below, Constant(bailout)); comment("Same near test"); comment("if (src.near != dst.near) goto bailout;"); movl(ebx, Address(eax, Constant(Oop::klass_offset()))); cmpl(ebx, Address(edx, Constant(Oop::klass_offset()))); jcc(not_equal, Constant(bailout)); comment("load the instance_size"); movl(ebx, Address(ebx, Constant(JavaNear::klass_offset()))); movsxw(ebx, Address(ebx, Constant(FarClass::instance_size_offset()))); comment("if (instance_size != size_type_array_1()) goto try_2_byte"); cmpl(ebx, Constant(InstanceSize::size_type_array_1)); jcc(not_equal, Constant(try_2_byte)); leal(esi, Address(eax, esi, times_1, Constant(Array::base_offset()))); leal(edi, Address(edx, edi, times_1, Constant(Array::base_offset()))); jmp(Constant(cont)); bind(try_2_byte); comment("if (instance_size != size_type_array_2()) goto try_4_byte"); cmpl(ebx, Constant(InstanceSize::size_type_array_2)); jcc(not_equal, Constant(try_4_byte)); leal(esi, Address(eax, esi, times_2, Constant(Array::base_offset()))); leal(edi, Address(edx, edi, times_2, Constant(Array::base_offset()))); shll(ecx, Constant(1)); jmp(Constant(cont)); bind(try_4_byte); comment("if (instance_size == size_type_array_4()) goto do_4_byte"); cmpl(ebx, Constant(InstanceSize::size_type_array_4)); jcc(equal, Constant(do_4_byte) ); comment("if (instance_size != size_obj_array()) goto bailout"); cmpl(ebx, Constant(InstanceSize::size_obj_array)); jcc(not_equal, Constant(bailout)); comment("if (dst < old_generation_end) goto bailout"); cmpl( edx, Address( Constant( "_old_generation_end" ) ) ); jcc( below, Constant(bailout)); bind(do_4_byte); leal(esi, Address(eax, esi, times_4, Constant(Array::base_offset()))); leal(edi, Address(edx, edi, times_4, Constant(Array::base_offset()))); shll(ecx, Constant(2)); bind(cont); comment("memmove(edi, esi, ecx);"); pushl(ecx); pushl(esi); pushl(edi); call(Constant("memmove")); addl(esp, Constant(16)); ret(Constant(5 * BytesPerStackElement)); comment("Bail out to the general arraycopy implementation"); bind(bailout); comment("pop method"); popl(ebx); if (AddExternCUnderscore) { emit_instruction("jmp _interpreter_method_entry"); } else { emit_instruction("jmp interpreter_method_entry"); } rom_linkable_entry_end(); // native_system_arraycopy_entry }
void NativeGenerator::generate_native_math_entries() { comment_section("Native entry points for math functions"); int offset = 0; #if ENABLE_FLOAT stop_code_segment(); start_data_segment(); stop_data_segment(); start_code_segment(); // Generate sinus entry. offset = 0; rom_linkable_entry("native_math_sin_entry"); comment("store return address"); popl(edi); pop_double(eax, ecx); pushl(ecx); pushl(eax); call(Constant("jvm_sin")); addl(esp, Constant(8)); push_from_fpu_stack(double_tag, offset, true); jmp(edi); rom_linkable_entry_end(); // native_math_sin_entry // Generate cosinus entry. offset = 0; rom_linkable_entry("native_math_cos_entry"); comment("store return address"); popl(edi); pop_double(eax, ecx); pushl(ecx); pushl(eax); call(Constant("jvm_cos")); addl(esp, Constant(8)); push_from_fpu_stack(double_tag, offset, true); jmp(edi); rom_linkable_entry_end(); // native_math_cos_entry // Generate tangent entry. offset = 0; rom_linkable_entry("native_math_tan_entry"); comment("store return address"); popl(edi); pop_double(eax, ecx); pushl(ecx); pushl(eax); call(Constant("jvm_tan")); addl(esp, Constant(8)); push_from_fpu_stack(double_tag, offset, true); jmp(edi); rom_linkable_entry_end(); // native_math_tan_entry // Generate square root entry. offset = 0; rom_linkable_entry("native_math_sqrt_entry"); comment("store return address"); popl(edi); pop_double(eax, ecx); pushl(ecx); pushl(eax); call(Constant("jvm_sqrt")); addl(esp, Constant(8)); push_from_fpu_stack(double_tag, offset, true); jmp(edi); rom_linkable_entry_end(); // native_math_sqrt_entry // Generate ceil entry. offset = 0; rom_linkable_entry("native_math_ceil_entry"); comment("store return address"); popl(edi); pop_double(eax, ecx); pushl(ecx); pushl(eax); call(Constant("jvm_ceil")); addl(esp, Constant(8)); push_from_fpu_stack(double_tag, offset, true); jmp(edi); rom_linkable_entry_end(); // native_math_ceil_entry // Generate floor entry. offset = 0; rom_linkable_entry("native_math_floor_entry"); comment("store return address"); popl(edi); pop_double(eax, ecx); pushl(ecx); pushl(eax); call(Constant("jvm_floor")); addl(esp, Constant(8)); push_from_fpu_stack(double_tag, offset, true); jmp(edi); rom_linkable_entry_end(); // native_math_floor_entry #endif /* ENABLE_FLOAT */ }
void NativeGenerator::generate_native_string_entries() { comment_section("Native entry points for string functions"); { //--------------------java.lang.String.indexof0--------------------------- rom_linkable_entry("native_string_indexof0_entry"); wtk_profile_quick_call(/* param_size*/ 2); comment("Pop the return address"); popl(edi); comment("Push zero for fromIndex"); pushl(Constant(0)); comment("Push back the return address"); pushl(edi); jmp(Constant("native_string_indexof_entry")); rom_linkable_entry_end(); // native_string_indexof0_entry //--------------------java.lang.String.indexof--------------------------- rom_linkable_entry("native_string_indexof_entry"); Label cont, loop, test, failure, success; wtk_profile_quick_call(/* param_size*/ 3); comment("Pop the return address"); popl(edi); comment("Pop the argument: fromIndex"); pop_int(eax, eax); comment("Pop the argument: ch"); pop_int(ebx, ebx); comment("Pop the receiver"); pop_obj(ecx, ecx); cmpl(ebx, Constant(0xFFFF)); jcc(greater, Constant(failure)); cmpl(eax, Constant(0)); jcc(greater_equal, Constant(cont)); movl(eax, Constant(0)); bind(cont); movl(esi, Address(ecx, Constant(String::count_offset()))); comment("if (fromIndex >= count) { return -1; }"); cmpl(eax, esi); jcc(greater_equal, Constant(failure)); movl(edx, Address(ecx, Constant(String::offset_offset()))); addl(eax, edx); // i = offset + fromIndex addl(edx, esi); // int max = offset + count; movl(esi, Address(ecx, Constant(String::value_offset()))); // v = value. jmp(Constant(test)); bind(loop); cmpw(Address(esi, eax, times_2, Constant(Array::base_offset())), ebx); jcc(equal, Constant(success)); incl(eax); bind(test); cmpl(eax, edx); jcc(less, Constant(loop)); comment("Return -1 by pushing the value and jumping to the return address"); bind(failure); push_int(-1); jmp(edi); comment("Return i - offset by pushing the value and jumping to the return address"); bind(success); movl(esi, Address(ecx, Constant(String::offset_offset()))); // i = offset + fromIndex subl(eax, esi); push_int(eax); jmp(edi); rom_linkable_entry_end(); // native_string_indexof_entry } //----------------------java.lang.String.charAt--------------------------- { rom_linkable_entry("native_string_charAt_entry"); if (AddExternCUnderscore) { emit_instruction("jmp _interpreter_method_entry"); } else { emit_instruction("jmp interpreter_method_entry"); } rom_linkable_entry_end(); } //----------------------java.lang.String(java.lang.StringBuffer)------------- { rom_linkable_entry("native_string_init_entry"); if (AddExternCUnderscore) { emit_instruction("jmp _interpreter_method_entry"); } else { emit_instruction("jmp interpreter_method_entry"); } rom_linkable_entry_end(); } //----------------------java.lang.String.equals(java.lang.Object)------------ { rom_linkable_entry("native_string_equals_entry"); if (AddExternCUnderscore) { emit_instruction("jmp _interpreter_method_entry"); } else { emit_instruction("jmp interpreter_method_entry"); } rom_linkable_entry_end(); } //----------------------java.lang.String.indexOf(java.lang.String)----------- { rom_linkable_entry("native_string_indexof0_string_entry"); if (AddExternCUnderscore) { emit_instruction("jmp _interpreter_method_entry"); } else { emit_instruction("jmp interpreter_method_entry"); } rom_linkable_entry_end(); } //----------------------java.lang.String.indexOf(java.lang.String)----------- { rom_linkable_entry("native_string_indexof_string_entry"); if (AddExternCUnderscore) { emit_instruction("jmp _interpreter_method_entry"); } else { emit_instruction("jmp interpreter_method_entry"); } rom_linkable_entry_end(); } //----------------------java.lang.String.compareTo--------------------------- { // java.lang.String.compareTo // Method int compareTo(java.lang.String) rom_linkable_entry("native_string_compareTo_entry"); wtk_profile_quick_call(/* param_size*/ 2); comment("preserve method"); pushl(ebx); // 8 is return address plus pushed method int str1_offset = JavaFrame::arg_offset_from_sp(0) + 8, str0_offset = JavaFrame::arg_offset_from_sp(1) + 8; comment("load arguments to registers"); movl(ecx, Address(esp, Constant(str1_offset))); movl(eax, Address(esp, Constant(str0_offset))); // eax: str0: this String // ebx: str1: String to compare against Label bailout; comment("Null check"); testl(ecx, ecx); jcc(zero, Constant(bailout)); comment("get str0.value[]"); movl(esi, Address(eax, Constant(String::value_offset()))); comment("get str0.offset"); movl(ebx, Address(eax, Constant(String::offset_offset()))); comment("compute start of character data"); leal(esi, Address(esi, ebx, times_2, Constant(Array::base_offset()))); comment("get str0.count"); movl(eax, Address(eax, Constant(String::count_offset()))); comment("get str1.value[]"); movl(edi, Address(ecx, Constant(String::value_offset()))); comment("get str1.offset"); movl(ebx, Address(ecx, Constant(String::offset_offset()))); comment("compute start of character data"); leal(edi, Address(edi, ebx, times_2, Constant(Array::base_offset()))); comment("get str1.count"); movl(ebx, Address(ecx, Constant(String::count_offset()))); // esi = str0 start of character data // edi = str1 start of character data // eax = str0 length // ebx = str1 length Label str1_longest; subl(eax, ebx); jcc(greater_equal, Constant(str1_longest)); // str1 is longer than str0 addl(ebx, eax); bind(str1_longest); // esi = str0 start of character data // edi = str1 start of character data // eax = str0.count - str1.count // ebx = min(str0.count, str1.count) // save str0.count - str1.count, we might need it later pushl(eax); xorl(ecx, ecx); Label loop, check_lengths, done; bind(loop); cmpl(ecx, ebx); jcc(above_equal, Constant(check_lengths)); movzxw(eax, Address(esi, ecx, times_2)); movzxw(edx, Address(edi, ecx, times_2)); subl(eax, edx); jcc(not_equal, Constant(done)); incl(ecx); jmp(Constant(loop)); bind(check_lengths); movl(eax, Address(esp)); bind(done); popl(ebx); // remove saved length difference // Push result on stack and return to caller popl(ebx); // remove method popl(edi); // pop return address addl(esp, Constant(2 * BytesPerStackElement)); // remove arguments push_int(eax); // push result jmp(edi); // return comment("Bail out to the general compareTo implementation"); bind(bailout); comment("pop method"); popl(ebx); if (AddExternCUnderscore) { emit_instruction("jmp _interpreter_method_entry"); } else { emit_instruction("jmp interpreter_method_entry"); } rom_linkable_entry_end(); // native_string_compareTo_entry } //----------------------java.lang.String.endsWith---------------- { // java.lang.String.endsWith // Method boolean endsWith(java.lang.String) rom_linkable_entry("native_string_endsWith_entry"); wtk_profile_quick_call(/* param_size*/ 2); Label bailout; // 4 is return address int suffix_offset = JavaFrame::arg_offset_from_sp(0) + 4, this_offset = JavaFrame::arg_offset_from_sp(1) + 4; comment("load arguments to registers"); movl(eax, Address(esp, Constant(suffix_offset))); cmpl(eax, Constant(0)); jcc(equal, Constant(bailout)); movl(ecx, Address(esp, Constant(this_offset))); comment("Pop the return address"); popl(edi); movl(edx, Address(ecx, Constant(String::count_offset()))); subl(edx, Address(eax, Constant(String::count_offset()))); comment("Push (this.count - suffix.count) for toffset"); pushl(edx); comment("Push back the return address"); pushl(edi); jmp(Constant("native_string_startsWith_entry")); comment("Bail out to the general startsWith implementation"); bind(bailout); if (AddExternCUnderscore) { emit_instruction("jmp _interpreter_method_entry"); } else { emit_instruction("jmp interpreter_method_entry"); } rom_linkable_entry_end(); // native_string_endsWith_entry } //----------------------java.lang.String.startsWith---------------- { // java.lang.String.startsWith // Method boolean startsWith(java.lang.String) rom_linkable_entry("native_string_startsWith0_entry"); wtk_profile_quick_call(/* param_size*/ 2); Label bailout; // 4 is return address int prefix_offset = JavaFrame::arg_offset_from_sp(0) + 4; comment("Check if prefix is null"); cmpl(Address(esp, Constant(prefix_offset)), Constant(0)); jcc(equal, Constant(bailout)); comment("Pop the return address"); popl(edi); comment("Push zero for toffset"); pushl(Constant(0)); comment("Push back the return address"); pushl(edi); jmp(Constant("native_string_startsWith_entry")); comment("Bail out to the general startsWith implementation"); bind(bailout); if (AddExternCUnderscore) { emit_instruction("jmp _interpreter_method_entry"); } else { emit_instruction("jmp interpreter_method_entry"); } rom_linkable_entry_end(); // native_string_startsWith0_entry } { // ----------- java.lang.String.startsWith ------------------------------ // Method boolean startsWith(java.lang.String,int) rom_linkable_entry("native_string_startsWith_entry"); wtk_profile_quick_call(/* param_size*/ 3); Label bailout, return_false; // 4 is return address int prefix_offset = JavaFrame::arg_offset_from_sp(1) + 4; comment("Check if prefix is null"); cmpl(Address(esp, Constant(prefix_offset)), Constant(0)); jcc(equal, Constant(bailout)); comment("Pop the return address"); popl(edi); comment("Pop the argument: toffset"); pop_int(edx, edx); comment("Pop the argument: prefix"); pop_obj(eax, eax); comment("Pop the receiver"); pop_obj(ecx, ecx); comment("Preserve the return address"); pushl(edi); // ecx: this String // eax: prefix cmpl(edx, Constant(0)); jcc(less, Constant(return_false)); comment("if (toffset > this.count - prefix.count) return false;"); movl(ebx, Address(ecx, Constant(String::count_offset()))); subl(ebx, Address(eax, Constant(String::count_offset()))); cmpl(edx, ebx); jcc(greater, Constant(return_false)); comment("get this.value[]"); movl(esi, Address(ecx, Constant(String::value_offset()))); comment("get this.offset"); movl(ebx, Address(ecx, Constant(String::offset_offset()))); comment("add toffset"); addl(ebx, edx); comment("compute start of character data"); leal(esi, Address(esi, ebx, times_2, Constant(Array::base_offset()))); comment("get prefix.value[]"); movl(edi, Address(eax, Constant(String::value_offset()))); comment("get prefix.offset"); movl(ebx, Address(eax, Constant(String::offset_offset()))); comment("compute start of character data"); leal(edi, Address(edi, ebx, times_2, Constant(Array::base_offset()))); comment("get prefix.count"); movl(ecx, Address(eax, Constant(String::count_offset()))); comment("get the number of bytes to compare"); shll(ecx, Constant(1)); comment("memcmp(edi, esi, ecx);"); pushl(ecx); pushl(esi); pushl(edi); if (GenerateInlineAsm) { // VC++ treats memcmp() as an intrinsic function and would cause // reference to memcmp in Interpreter_i386.c to fail to compile. call(Constant("memcmp_from_interpreter")); } else { call(Constant("memcmp")); } addl(esp, Constant(12)); cmpl(eax, Constant(0)); jcc(not_equal, Constant(return_false)); // Push 1 on stack and return to caller popl(edi); // pop return address push_int(1); // push result jmp(edi); // return bind(return_false); // Push 0 on stack and return to caller popl(edi); // pop return address push_int(0); // push result jmp(edi); // return comment("Bail out to the general startsWith implementation"); bind(bailout); if (AddExternCUnderscore) { emit_instruction("jmp _interpreter_method_entry"); } else { emit_instruction("jmp interpreter_method_entry"); } rom_linkable_entry_end(); // native_string_startsWith_entry } }
void InterpreterStubs::generate_interpreter_fill_in_tags() { comment_section("Interpreter fill in tags"); entry("interpreter_fill_in_tags"); comment("eax: return address of method"); comment("ebx: method"); comment("ecx: size of parameters. Guaranteed to be >= 1"); comment("edx: call info from call site"); comment("Must preserve eax, ebx, ecx"); // stack layout: // sp return address of caller // --> argument n // --> ... // --> argument 0 Label extended_call_info; comment("Compact call info or normal call info?"); testl(edx, edx); jcc(positive, Constant(extended_call_info)); Label loop_entry, loop_condition; comment("We have a compact call info"); movl(edi, ecx); bind(loop_entry); decl(edi); comment("Store int tag"); movl(Address(esp, edi, times_8, Constant(BytesPerWord)), Constant(int_tag)); comment("Test the bit in the call info"); GUARANTEE(CallInfo::format1_tag_start == 0, "Tag must start at bit position 0 for this code to work"); btl(edx, edi); jcc(carry_clear, Constant(loop_condition)); comment("Store obj tag"); movl(Address(esp, edi, times_8, Constant(BytesPerWord)), Constant(obj_tag)); bind(loop_condition); testl(edi, edi); jcc(not_zero, Constant(loop_entry)); ret(); bind(extended_call_info); comment("Normal call info"); // The following code is slightly complicated. "Bit offset" below // pretends like the callinfo's are in a bit array, as follows: // Callinfo describing bci and offset // Size [16 bits] and stack info 0-3 // Stack info 4-11 // We ignore the fact that each of these words is preceded by a byte // that makes it look like an instruction. pushl(ecx); pushl(ebx); Label loopx_entry, loopx_done; comment("Bit offset of first argument in CallInfo array"); movzxw(edx, Address(eax, Constant(5 + 1))); // total number of locals/expr subl(edx, ecx); // number of locals/expr belonging to callee shll(edx, Constant(2)); // number of bits per nybble addl(edx, Constant(32 + 16)); // 48 bits is the 32 bit callinfo and 16bit size info comment("Decrement argument count; move to more convenient register"); leal(esi, Address(ecx, Constant(-1))); comment("Location of tag of esi-th local"); leal(ebx, Address(esp, Constant(3 * BytesPerWord))); bind(loopx_entry); comment("eax holds the return address"); comment("ebx holds address of the esi-th tag"); comment("esi is the local whose tag we are setting"); comment("edx contains the bit offset of Local 0 in the CallInfo array"); comment("Get bit offset of esi-th local"); leal(ecx, Address(edx, esi, times_4)); comment("From bit offset, get word offset, then multiply by 5"); movl(edi, ecx); shrl(edi, Constant(5)); leal(edi, Address(edi, edi, times_4)); comment("Get the appropriate CallInfo word; extract the nybble"); movl(edi, Address(eax, edi, times_1, Constant(1))); shrl(edi); andl(edi, Constant(0xF)); comment("Tag is (1 << value) >> 1. This is 0 when value == 0"); movl(ecx, edi); movl(edi, Constant(1)); shll(edi); shrl(edi, Constant(1)); comment("Store the tag"); movl(Address(ebx), edi); comment("Are we done?"); decl(esi); addl(ebx, Constant(8)); testl(esi, esi); jcc(greater_equal, Constant(loopx_entry)); bind(loopx_done); popl(ebx); popl(ecx); ret(); entry_end(); // interpreter_fill_in_tags }