void InterpreterStubs::generate_interpreter_timer_tick() { comment_section("Interpreter call timer_tick"); entry("interpreter_timer_tick"); interpreter_call_vm(Constant("timer_tick"), T_VOID); dispatch_next(); entry_end(); // interpreter_timer_tick #if ENABLE_PAGE_PROTECTION stop_code_segment(); start_data_segment(); if (GenerateGNUCode || GenerateInlineAsm) { align(PROTECTED_PAGE_SIZE); define_array_begin("unsigned char", "_protected_page"); for (int i = 0; i < PROTECTED_PAGE_SIZE; i++) { define_byte_element(Constant(0)); } define_array_end(); } else { // MASM doesn't allow 4096-byte alignment, // so surround the protected area with 4K padding. // This will certainly add 8K of static footprint, // but who cares about the size of win32_i386 binary! define_byte(Constant(0), PROTECTED_PAGE_SIZE); define_long(Constant(0), PROTECTED_PAGE_SIZE / BytesPerWord, "_protected_page"); define_byte(Constant(0), PROTECTED_PAGE_SIZE); } stop_data_segment(); start_code_segment(); #endif }
void InterpreterStubs::generate_interpreter_throw_exceptions() { comment_section("Interpreter exception throwers"); entry("interpreter_throw_ArrayIndexOutOfBoundsException", 0); interpreter_call_vm(Constant("array_index_out_of_bounds_exception"), T_VOID); entry_end(); // interpreter_throw_ArrayIndexOutOfBoundsException entry("interpreter_throw_NullPointerException", 0); interpreter_call_vm(Constant("null_pointer_exception"), T_VOID); entry_end(); // interpreter_throw_NullPointerException entry("interpreter_throw_IllegalMonitorStateException", 0); interpreter_call_vm(Constant("illegal_monitor_state_exception"), T_VOID); entry_end(); // interpreter_throw_IllegalMonitorStateException entry("interpreter_throw_ArithmeticException", 0); interpreter_call_vm(Constant("arithmetic_exception"), T_VOID); entry_end(); // interpreter_throw_ArithmeticException entry("interpreter_throw_IncompatibleClassChangeError", 0); interpreter_call_vm(Constant("incompatible_class_change_error"), T_VOID); entry_end(); // interpreter_throw_IncompatibleClassChangeError if (GenerateDebugAssembly) { entry("interpreter_throw_InternalStackTagException", 0); interpreter_call_vm(Constant("internal_stack_tag_exception"), T_VOID); entry_end(); // interpreter_throw_InternalStackTagException } }
void CompilerStubs::generate_compiler_new_object() { comment_section("Compiler new object (any size)"); comment("Register edx holds the instance size, register ebx holds the prototypical near of the instance class"); Label slow_case; entry("compiler_new_object"); comment("Get _inline_allocation_top"); movl(eax, Address(Constant("_inline_allocation_top"))); comment("Compute new top"); leal(ecx, Address(eax, edx, times_1)); if (GenerateDebugAssembly) { comment("Check ExcessiveGC"); testl(Address(Constant("ExcessiveGC")), Constant(0)); jcc(not_zero, Constant(slow_case)); } comment("Compare against _inline_allocation_end"); cmpl(ecx, Address(Constant("_inline_allocation_end"))); jcc(above, Constant(slow_case)); comment("Allocation succeeded, set _inline_allocation_top"); movl(Address(Constant("_inline_allocation_top")), ecx); comment("Set prototypical near in object; no need for write barrier"); movl(Address(eax), ebx); comment("Compute remaining size"); decrement(edx, oopSize); comment("One-word object?"); Label init_done; jcc(zero, Constant(init_done)); comment("Zero object fields"); xorl(ecx, ecx); Label init_loop; bind(init_loop); movl(Address(eax, edx, times_1), ecx); decrement(edx, oopSize); jcc(not_zero, Constant(init_loop)); bind(init_done); comment("The newly allocated object is in register eax"); ret(); comment("Slow case - call the VM runtime system"); bind(slow_case); leal(eax, Address(Constant("newobject"))); goto_shared_call_vm(T_OBJECT); entry_end(); // compiler_new_object }
void SourceAssembler::start() { _current_segment = NO_SEGMENT; // Emit the header. emit_comment("Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved."); emit_comment("DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER"); emit_comment(""); emit_comment("This program is free software; you can redistribute it and/or"); emit_comment("modify it under the terms of the GNU General Public License version"); emit_comment("2 only, as published by the Free Software Foundation."); emit_comment(""); emit_comment("This program is distributed in the hope that it will be useful, but"); emit_comment("WITHOUT ANY WARRANTY; without even the implied warranty of"); emit_comment("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU"); emit_comment("General Public License version 2 for more details (a copy is"); emit_comment("included at /legal/license.txt)."); emit_comment(""); emit_comment("You should have received a copy of the GNU General Public License"); emit_comment("version 2 along with this work; if not, write to the Free Software"); emit_comment("Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA"); emit_comment("02110-1301 USA"); emit_comment(""); emit_comment("Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa"); emit_comment("Clara, CA 95054 or visit www.sun.com if you need additional"); emit_comment("information or have any questions."); emit("\n"); if (GenerateInlineAsm) { if (1) { // visual c++ emit("#define __DECLSPEC_ALIGN(x)\n"); } else { emit("#define __DECLSPEC_ALIGN(x) __declspec(align(x))\n"); } } // Make sure people know that this file shouldn't be edited. comment_section("Generated assembly file -- do *not* edit"); emit("\n"); // Emit the platform and model specifiers. if (!GenerateGNUCode) { if (!GenerateInlineAsm) { emit("\t.486P\n"); emit("\t.MODEL flat, C\n\n"); } } else { emit("\t.arch i486\n"); } start_code_segment(); }
void InterpreterStubs::generate_interpreter_deoptimization_entry() { comment_section("Interpreter deoptimization entry"); entry("interpreter_deoptimization_entry"); // Define an interpreter call info. define_call_info(); comment("Restore bytecode and locals pointers"); movl(esi, Address(ebp, Constant(JavaFrame::bcp_store_offset()))); movl(edi, Address(ebp, Constant(JavaFrame::locals_pointer_offset()))); // Dispatch to the next bytecode. dispatch_next(); entry_end(); // interpreter_deoptimization_entry }
void SourceAssembler::start() { // header comment("Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved."); comment("DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER"); comment(""); comment("This program is free software; you can redistribute it and/or"); comment("modify it under the terms of the GNU General Public License version"); comment("2 only, as published by the Free Software Foundation."); comment(""); comment("This program is distributed in the hope that it will be useful, but"); comment("WITHOUT ANY WARRANTY; without even the implied warranty of"); comment("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU"); comment("General Public License version 2 for more details (a copy is"); comment("included at /legal/license.txt)."); comment(""); comment("You should have received a copy of the GNU General Public License"); comment("version 2 along with this work; if not, write to the Free Software"); comment("Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA"); comment("02110-1301 USA"); comment(""); comment("Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa"); comment("Clara, CA 95054 or visit www.sun.com if you need additional"); comment("information or have any questions."); // make sure people know that this file shouldn't be edited comment_section("Generated assembly file -- do *not* edit"); if (!GenerateGNUCode) { stream()->print_cr("tos_val RN %d", tos_val); stream()->print_cr("tos_tag RN %d", tos_tag); stream()->print_cr("tmp0 RN %d", tmp0); stream()->print_cr("tmp1 RN %d", tmp1); stream()->print_cr("bcode RN %d", bcode); stream()->print_cr("bcp RN %d", bcp); stream()->print_cr("gp RN %d", gp); stream()->print_cr("locals RN %d", locals); // sl = r10 // fp = r11 stream()->print_cr("tmp2 RN %d", tmp2); // sp = r13 stream()->print_cr("tmp3 RN %d", tmp3); // lr is also r14 // pc == r15 } }
void InterpreterStubs::generate_interpreter_unwind_activation() { comment_section("Interpreter unwind activation"); entry("interpreter_unwind_activation"); comment("The exception is the single item on the interpreter stack"); comment("Unlock and remove the activation"); unlock_activation(true); comment("Remove exception from the stack"); pop_obj(eax, eax); remove_activation(edx); get_thread(ecx); jmp(Constant("shared_code_for_handling_of_exception_forwarding")); entry_end(); // interpreter_unwind_activation }
void InterpreterStubs::generate_interpreter_rethrow_exception() { comment_section("Interpreter rethrow exception"); comment("Register eax holds the exception; Interpreter state is not in registers"); entry("interpreter_rethrow_exception"); comment("Restore bytecode and locals pointers"); movl(esi, Address(ebp, Constant(JavaFrame::bcp_store_offset()))); movl(edi, Address(ebp, Constant(JavaFrame::locals_pointer_offset()))); comment("Mark the bytecode pointer as being inside an exception"); addl(esi, Constant(JavaFrame::exception_frame_flag)); comment("Clear the expression stack"); movl(esp, Address(ebp, Constant(JavaFrame::stack_bottom_pointer_offset()))); comment("Push the exception on the expression stack"); push_obj(eax); comment("Get exception handler bci for exception"); interpreter_call_vm(Constant("exception_handler_bci_for_exception"), T_INT); comment("Check if we got a bci - otherwise unwind the activation"); cmpl(eax, Constant(-1)); jcc(equal, Constant("interpreter_unwind_activation")); #if ENABLE_JAVA_DEBUGGER Label skip; cmpb(Address(Constant("_debugger_active")), Constant(0)); jcc(equal, Constant(skip)); movl(edx, eax); interpreter_call_vm(Constant("handle_caught_exception"), T_VOID); comment("Re-get exception handler bci for exception"); interpreter_call_vm(Constant("exception_handler_bci_for_exception"), T_INT); bind(skip); #endif comment("Convert the bytecode index into a bytecode pointer"); movl(ecx, Address(ebp, Constant(JavaFrame::method_offset()))); leal(esi, Address(ecx, eax, times_1, Constant(Method::base_offset()))); // Dispatch to the exception handler. dispatch_next(); entry_end(); // interpreter_rethrow_exception }
void InterpreterStubs::generate_interpreter_call_vm_dispatch() { comment_section("Interpreter call VM - and dispatch to the bytecode returned by the VM upon termination"); entry("interpreter_call_vm_dispatch"); comment("Save bytecode pointer"); movl(Address(ebp, Constant(JavaFrame::bcp_store_offset())), esi); comment("Call the shared call vm and disregard any return value"); call_shared_call_vm(T_INT); comment("Restore bytecode pointer"); movl(esi, Address(ebp, Constant(JavaFrame::bcp_store_offset()))); comment("Restore locals pointer"); movl(edi, Address(ebp, Constant(JavaFrame::locals_pointer_offset()))); comment("Dispatch to next byte code"); jmp(Address(no_reg, eax, times_4, Constant("interpreter_dispatch_table"))); entry_end(); // interpreter_call_vm_dispatch }
void InterpreterStubs::generate_interpreter_call_vm_redo() { #if ENABLE_JAVA_DEBUGGER Label check_breakpoint, no_breakpoint; #endif comment_section("Interpreter call VM - and repeat current bytecode upon termination"); entry("interpreter_call_vm_redo"); comment("Save bytecode pointer"); movl(Address(ebp, Constant(JavaFrame::bcp_store_offset())), esi); comment("Call the shared call vm and disregard any return value"); call_shared_call_vm(T_VOID); comment("Restore bytecode pointer"); movl(esi, Address(ebp, Constant(JavaFrame::bcp_store_offset()))); comment("Restore locals pointer"); movl(edi, Address(ebp, Constant(JavaFrame::locals_pointer_offset()))); #if ENABLE_JAVA_DEBUGGER comment("Check to see if we are connected to a debugger"); cmpb(Address(Constant("_debugger_active")), Constant(0)); jcc(not_zero, Constant(check_breakpoint)); bind(no_breakpoint); comment("Not debugging, so just dispatch"); dispatch_next(0); bind(check_breakpoint); comment("We are debugging, so let's see if we just replaced a breakpoint opcode"); cmpb(Address(esi), Constant(Bytecodes::_breakpoint)); jcc(not_zero, Constant(no_breakpoint)); comment("There is a breakpoint in the code, so that means that eax has the correct opcode"); comment("So just jmp directly without using esi"); andl(eax, Constant(0xFF)); movl(ebx, eax); jmp(Address(no_reg, ebx, times_4, Constant("interpreter_dispatch_table"))); #else dispatch_next(0); #endif entry_end(); // interpreter_call_vm_redo }
void InterpreterStubs::generate_interpreter_rethrow_exception_init() { comment_section("Interpreter rethrow exception init"); comment("Register eax holds the exception; Interpreter state is not in registers"); entry("interpreter_rethrow_exception_init"); #if ENABLE_JAVA_DEBUGGER Label skip; cmpb(Address(Constant("_debugger_active")), Constant(0)); jcc(equal, Constant(skip)); comment("push the exception object so we don't nuke it"); push_obj(eax); comment("call debugger code to store relevant info about where exception happened"); interpreter_call_vm(Constant("handle_exception_info"), T_VOID); pop_obj(eax, edx); bind(skip); #endif if (GenerateInlineAsm) jmp(Constant("interpreter_rethrow_exception_init")); else comment("fall through to rethrow_exception"); // IMPL_NOTE: FALLTHROUGH entry_end(); // interpreter_rethrow_exception_init }
void CompilerStubs::generate_compiler_idiv_irem() { comment_section("Compiler integer divide and remainder"); comment("Register eax holds the dividend, register ebx holds the divisor"); entry("compiler_idiv_irem"); const int min_int = 0x80000000; Label normal_case, special_case; Label throw_exception; testl(ebx,ebx); jcc(equal, Constant(throw_exception)); // Check for special case cmpl(eax, Constant(min_int)); jcc(not_equal, Constant(normal_case)); xorl(edx, edx); // Prepare edx for possible special case (where remainder = 0) cmpl(ebx, Constant(-1)); jcc(equal, Constant(special_case)); // Handle normal case bind(normal_case); cdql(); idivl(ebx); // Normal and special case exit bind(special_case); ret(); bind(throw_exception); comment("Throw a DivisionByZeroException"); leal(eax, Address(Constant("division_by_zero_exception"))); goto_shared_call_vm(T_VOID); entry_end(); // compiler_idiv_irem }
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 CompilerStubs::generate_compiler_new_obj_array() { comment_section("Compiler stub: new object array"); comment("- ebx holds the prototypical near of the array class"); entry("compiler_new_obj_array"); comment("Get array length"); // add BytesPerWord for return address movl(edx, Address(esp, Constant(BytesPerWord + JavaFrame::arg_offset_from_sp(0)))); Label slow_case; comment("Check if the array length is too large or negative"); cmpl(edx, Constant(maximum_safe_array_length)); jcc(above, Constant(slow_case)); comment("Get _inline_allocation_top"); movl(eax, Address(Constant("_inline_allocation_top"))); if (GenerateDebugAssembly) { comment("Check ExcessiveGC"); testl(Address(Constant("ExcessiveGC")), Constant(0)); jcc(not_zero, Constant(slow_case)); } comment("Compute new top"); leal(ecx, Address(eax, edx, times_4, Constant(Array::base_offset()))); comment("Check for overflow"); cmpl(ecx, eax); jcc(below, Constant(slow_case)); comment("Compare against _inline_allocation_end"); cmpl(ecx, Address(Constant("_inline_allocation_end"))); jcc(above, Constant(slow_case)); comment("Allocation succeeded, set _inline_allocation_top"); movl(Address(Constant("_inline_allocation_top")), ecx); comment("Set prototypical near in object; no need for write barrier"); movl(Address(eax), ebx); comment("Set the length"); movl(Address(eax, Constant(Array::length_offset())), edx); comment("Compute remaining size"); testl(edx, edx); comment("Empty array?"); Label init_done; jcc(equal, Constant(init_done)); comment("Zero array elements"); xorl(ecx, ecx); Label init_loop; bind(init_loop); movl(Address(eax, edx, times_4, Constant(Array::base_offset() - oopSize)), ecx); decrement(edx, 1); jcc(not_zero, Constant(init_loop)); bind(init_done); comment("The newly allocated array is in register eax"); ret(); comment("Slow case - call the VM runtime system"); bind(slow_case); leal(eax, Address(Constant("anewarray"))); goto_shared_call_vm(T_ARRAY); entry_end(); // compiler_new_obj_array }
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_thread_entries() { comment_section("Native entry points for thread functions"); // rom_linkable_entry("native_thread_enterLockObject_entry"); // jmp(Constant("Java_com_sun_cldchi_jvm_Thread_enterLockObject")); }
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 }