aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: * aoqi@0: */ aoqi@0: aoqi@0: #include "precompiled.hpp" aoqi@0: #include "interpreter/interpreter.hpp" aoqi@0: #include "interpreter/interpreterGenerator.hpp" aoqi@0: #include "interpreter/interpreterRuntime.hpp" aoqi@0: #include "interpreter/templateTable.hpp" aoqi@0: aoqi@0: #ifndef CC_INTERP aoqi@0: aoqi@0: # define __ _masm-> aoqi@0: aoqi@0: void TemplateInterpreter::initialize() { aoqi@0: if (_code != NULL) return; aoqi@0: // assertions aoqi@0: assert((int)Bytecodes::number_of_codes <= (int)DispatchTable::length, aoqi@0: "dispatch table too small"); aoqi@0: aoqi@0: AbstractInterpreter::initialize(); aoqi@0: aoqi@0: TemplateTable::initialize(); aoqi@0: aoqi@0: // generate interpreter aoqi@0: { ResourceMark rm; aoqi@0: TraceTime timer("Interpreter generation", TraceStartupTime); aoqi@0: int code_size = InterpreterCodeSize; aoqi@0: NOT_PRODUCT(code_size *= 4;) // debug uses extra interpreter code space aoqi@0: _code = new StubQueue(new InterpreterCodeletInterface, code_size, NULL, aoqi@0: "Interpreter"); aoqi@0: InterpreterGenerator g(_code); aoqi@0: if (PrintInterpreter) print(); aoqi@0: } aoqi@0: aoqi@0: // initialize dispatch table aoqi@0: _active_table = _normal_table; aoqi@0: } aoqi@0: aoqi@0: //------------------------------------------------------------------------------------------------------------------------ aoqi@0: // Implementation of EntryPoint aoqi@0: aoqi@0: EntryPoint::EntryPoint() { aoqi@0: assert(number_of_states == 9, "check the code below"); aoqi@0: _entry[btos] = NULL; aoqi@0: _entry[ctos] = NULL; aoqi@0: _entry[stos] = NULL; aoqi@0: _entry[atos] = NULL; aoqi@0: _entry[itos] = NULL; aoqi@0: _entry[ltos] = NULL; aoqi@0: _entry[ftos] = NULL; aoqi@0: _entry[dtos] = NULL; aoqi@0: _entry[vtos] = NULL; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: EntryPoint::EntryPoint(address bentry, address centry, address sentry, address aentry, address ientry, address lentry, address fentry, address dentry, address ventry) { aoqi@0: assert(number_of_states == 9, "check the code below"); aoqi@0: _entry[btos] = bentry; aoqi@0: _entry[ctos] = centry; aoqi@0: _entry[stos] = sentry; aoqi@0: _entry[atos] = aentry; aoqi@0: _entry[itos] = ientry; aoqi@0: _entry[ltos] = lentry; aoqi@0: _entry[ftos] = fentry; aoqi@0: _entry[dtos] = dentry; aoqi@0: _entry[vtos] = ventry; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void EntryPoint::set_entry(TosState state, address entry) { aoqi@0: assert(0 <= state && state < number_of_states, "state out of bounds"); aoqi@0: _entry[state] = entry; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: address EntryPoint::entry(TosState state) const { aoqi@0: assert(0 <= state && state < number_of_states, "state out of bounds"); aoqi@0: return _entry[state]; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void EntryPoint::print() { aoqi@0: tty->print("["); aoqi@0: for (int i = 0; i < number_of_states; i++) { aoqi@0: if (i > 0) tty->print(", "); aoqi@0: tty->print(INTPTR_FORMAT, p2i(_entry[i])); aoqi@0: } aoqi@0: tty->print("]"); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: bool EntryPoint::operator == (const EntryPoint& y) { aoqi@0: int i = number_of_states; aoqi@0: while (i-- > 0) { aoqi@0: if (_entry[i] != y._entry[i]) return false; aoqi@0: } aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: //------------------------------------------------------------------------------------------------------------------------ aoqi@0: // Implementation of DispatchTable aoqi@0: aoqi@0: EntryPoint DispatchTable::entry(int i) const { aoqi@0: assert(0 <= i && i < length, "index out of bounds"); aoqi@0: return aoqi@0: EntryPoint( aoqi@0: _table[btos][i], aoqi@0: _table[ctos][i], aoqi@0: _table[stos][i], aoqi@0: _table[atos][i], aoqi@0: _table[itos][i], aoqi@0: _table[ltos][i], aoqi@0: _table[ftos][i], aoqi@0: _table[dtos][i], aoqi@0: _table[vtos][i] aoqi@0: ); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void DispatchTable::set_entry(int i, EntryPoint& entry) { aoqi@0: assert(0 <= i && i < length, "index out of bounds"); aoqi@0: assert(number_of_states == 9, "check the code below"); aoqi@0: _table[btos][i] = entry.entry(btos); aoqi@0: _table[ctos][i] = entry.entry(ctos); aoqi@0: _table[stos][i] = entry.entry(stos); aoqi@0: _table[atos][i] = entry.entry(atos); aoqi@0: _table[itos][i] = entry.entry(itos); aoqi@0: _table[ltos][i] = entry.entry(ltos); aoqi@0: _table[ftos][i] = entry.entry(ftos); aoqi@0: _table[dtos][i] = entry.entry(dtos); aoqi@0: _table[vtos][i] = entry.entry(vtos); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: bool DispatchTable::operator == (DispatchTable& y) { aoqi@0: int i = length; aoqi@0: while (i-- > 0) { aoqi@0: EntryPoint t = y.entry(i); // for compiler compatibility (BugId 4150096) aoqi@0: if (!(entry(i) == t)) return false; aoqi@0: } aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: address TemplateInterpreter::_remove_activation_entry = NULL; aoqi@0: address TemplateInterpreter::_remove_activation_preserving_args_entry = NULL; aoqi@0: aoqi@0: aoqi@0: address TemplateInterpreter::_throw_ArrayIndexOutOfBoundsException_entry = NULL; aoqi@0: address TemplateInterpreter::_throw_ArrayStoreException_entry = NULL; aoqi@0: address TemplateInterpreter::_throw_ArithmeticException_entry = NULL; aoqi@0: address TemplateInterpreter::_throw_ClassCastException_entry = NULL; aoqi@0: address TemplateInterpreter::_throw_NullPointerException_entry = NULL; aoqi@0: address TemplateInterpreter::_throw_StackOverflowError_entry = NULL; aoqi@0: address TemplateInterpreter::_throw_exception_entry = NULL; aoqi@0: aoqi@0: #ifndef PRODUCT aoqi@0: EntryPoint TemplateInterpreter::_trace_code; aoqi@0: #endif // !PRODUCT aoqi@0: EntryPoint TemplateInterpreter::_return_entry[TemplateInterpreter::number_of_return_entries]; aoqi@0: EntryPoint TemplateInterpreter::_earlyret_entry; aoqi@0: EntryPoint TemplateInterpreter::_deopt_entry [TemplateInterpreter::number_of_deopt_entries ]; aoqi@0: EntryPoint TemplateInterpreter::_continuation_entry; aoqi@0: EntryPoint TemplateInterpreter::_safept_entry; aoqi@0: aoqi@0: address TemplateInterpreter::_invoke_return_entry[TemplateInterpreter::number_of_return_addrs]; aoqi@0: address TemplateInterpreter::_invokeinterface_return_entry[TemplateInterpreter::number_of_return_addrs]; aoqi@0: address TemplateInterpreter::_invokedynamic_return_entry[TemplateInterpreter::number_of_return_addrs]; aoqi@0: aoqi@0: DispatchTable TemplateInterpreter::_active_table; aoqi@0: DispatchTable TemplateInterpreter::_normal_table; aoqi@0: DispatchTable TemplateInterpreter::_safept_table; aoqi@0: address TemplateInterpreter::_wentry_point[DispatchTable::length]; aoqi@0: aoqi@0: TemplateInterpreterGenerator::TemplateInterpreterGenerator(StubQueue* _code): AbstractInterpreterGenerator(_code) { aoqi@0: _unimplemented_bytecode = NULL; aoqi@0: _illegal_bytecode_sequence = NULL; aoqi@0: } aoqi@0: aoqi@0: static const BasicType types[Interpreter::number_of_result_handlers] = { aoqi@0: T_BOOLEAN, aoqi@0: T_CHAR , aoqi@0: T_BYTE , aoqi@0: T_SHORT , aoqi@0: T_INT , aoqi@0: T_LONG , aoqi@0: T_VOID , aoqi@0: T_FLOAT , aoqi@0: T_DOUBLE , aoqi@0: T_OBJECT aoqi@0: }; aoqi@0: aoqi@0: void TemplateInterpreterGenerator::generate_all() { aoqi@0: AbstractInterpreterGenerator::generate_all(); aoqi@0: aoqi@0: { CodeletMark cm(_masm, "error exits"); aoqi@0: _unimplemented_bytecode = generate_error_exit("unimplemented bytecode"); aoqi@0: _illegal_bytecode_sequence = generate_error_exit("illegal bytecode sequence - method not verified"); aoqi@0: } aoqi@0: aoqi@0: #ifndef PRODUCT aoqi@0: if (TraceBytecodes) { aoqi@0: CodeletMark cm(_masm, "bytecode tracing support"); aoqi@0: Interpreter::_trace_code = aoqi@0: EntryPoint( aoqi@0: generate_trace_code(btos), aoqi@0: generate_trace_code(ctos), aoqi@0: generate_trace_code(stos), aoqi@0: generate_trace_code(atos), aoqi@0: generate_trace_code(itos), aoqi@0: generate_trace_code(ltos), aoqi@0: generate_trace_code(ftos), aoqi@0: generate_trace_code(dtos), aoqi@0: generate_trace_code(vtos) aoqi@0: ); aoqi@0: } aoqi@0: #endif // !PRODUCT aoqi@0: aoqi@0: { CodeletMark cm(_masm, "return entry points"); aoqi@0: const int index_size = sizeof(u2); aoqi@0: for (int i = 0; i < Interpreter::number_of_return_entries; i++) { aoqi@0: Interpreter::_return_entry[i] = aoqi@0: EntryPoint( aoqi@0: generate_return_entry_for(itos, i, index_size), aoqi@0: generate_return_entry_for(itos, i, index_size), aoqi@0: generate_return_entry_for(itos, i, index_size), aoqi@0: generate_return_entry_for(atos, i, index_size), aoqi@0: generate_return_entry_for(itos, i, index_size), aoqi@0: generate_return_entry_for(ltos, i, index_size), aoqi@0: generate_return_entry_for(ftos, i, index_size), aoqi@0: generate_return_entry_for(dtos, i, index_size), aoqi@0: generate_return_entry_for(vtos, i, index_size) aoqi@0: ); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: { CodeletMark cm(_masm, "invoke return entry points"); aoqi@0: const TosState states[] = {itos, itos, itos, itos, ltos, ftos, dtos, atos, vtos}; aoqi@0: const int invoke_length = Bytecodes::length_for(Bytecodes::_invokestatic); aoqi@0: const int invokeinterface_length = Bytecodes::length_for(Bytecodes::_invokeinterface); aoqi@0: const int invokedynamic_length = Bytecodes::length_for(Bytecodes::_invokedynamic); aoqi@0: aoqi@0: for (int i = 0; i < Interpreter::number_of_return_addrs; i++) { aoqi@0: TosState state = states[i]; aoqi@0: Interpreter::_invoke_return_entry[i] = generate_return_entry_for(state, invoke_length, sizeof(u2)); aoqi@0: Interpreter::_invokeinterface_return_entry[i] = generate_return_entry_for(state, invokeinterface_length, sizeof(u2)); aoqi@0: Interpreter::_invokedynamic_return_entry[i] = generate_return_entry_for(state, invokedynamic_length, sizeof(u4)); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: { CodeletMark cm(_masm, "earlyret entry points"); aoqi@0: Interpreter::_earlyret_entry = aoqi@0: EntryPoint( aoqi@0: generate_earlyret_entry_for(btos), aoqi@0: generate_earlyret_entry_for(ctos), aoqi@0: generate_earlyret_entry_for(stos), aoqi@0: generate_earlyret_entry_for(atos), aoqi@0: generate_earlyret_entry_for(itos), aoqi@0: generate_earlyret_entry_for(ltos), aoqi@0: generate_earlyret_entry_for(ftos), aoqi@0: generate_earlyret_entry_for(dtos), aoqi@0: generate_earlyret_entry_for(vtos) aoqi@0: ); aoqi@0: } aoqi@0: aoqi@0: { CodeletMark cm(_masm, "deoptimization entry points"); aoqi@0: for (int i = 0; i < Interpreter::number_of_deopt_entries; i++) { aoqi@0: Interpreter::_deopt_entry[i] = aoqi@0: EntryPoint( aoqi@0: generate_deopt_entry_for(itos, i), aoqi@0: generate_deopt_entry_for(itos, i), aoqi@0: generate_deopt_entry_for(itos, i), aoqi@0: generate_deopt_entry_for(atos, i), aoqi@0: generate_deopt_entry_for(itos, i), aoqi@0: generate_deopt_entry_for(ltos, i), aoqi@0: generate_deopt_entry_for(ftos, i), aoqi@0: generate_deopt_entry_for(dtos, i), aoqi@0: generate_deopt_entry_for(vtos, i) aoqi@0: ); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: { CodeletMark cm(_masm, "result handlers for native calls"); aoqi@0: // The various result converter stublets. aoqi@0: int is_generated[Interpreter::number_of_result_handlers]; aoqi@0: memset(is_generated, 0, sizeof(is_generated)); aoqi@0: aoqi@0: for (int i = 0; i < Interpreter::number_of_result_handlers; i++) { aoqi@0: BasicType type = types[i]; aoqi@0: if (!is_generated[Interpreter::BasicType_as_index(type)]++) { aoqi@0: Interpreter::_native_abi_to_tosca[Interpreter::BasicType_as_index(type)] = generate_result_handler_for(type); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: { CodeletMark cm(_masm, "continuation entry points"); aoqi@0: Interpreter::_continuation_entry = aoqi@0: EntryPoint( aoqi@0: generate_continuation_for(btos), aoqi@0: generate_continuation_for(ctos), aoqi@0: generate_continuation_for(stos), aoqi@0: generate_continuation_for(atos), aoqi@0: generate_continuation_for(itos), aoqi@0: generate_continuation_for(ltos), aoqi@0: generate_continuation_for(ftos), aoqi@0: generate_continuation_for(dtos), aoqi@0: generate_continuation_for(vtos) aoqi@0: ); aoqi@0: } aoqi@0: aoqi@0: { CodeletMark cm(_masm, "safepoint entry points"); aoqi@0: Interpreter::_safept_entry = aoqi@0: EntryPoint( aoqi@0: generate_safept_entry_for(btos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)), aoqi@0: generate_safept_entry_for(ctos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)), aoqi@0: generate_safept_entry_for(stos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)), aoqi@0: generate_safept_entry_for(atos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)), aoqi@0: generate_safept_entry_for(itos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)), aoqi@0: generate_safept_entry_for(ltos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)), aoqi@0: generate_safept_entry_for(ftos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)), aoqi@0: generate_safept_entry_for(dtos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)), aoqi@0: generate_safept_entry_for(vtos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)) aoqi@0: ); aoqi@0: } aoqi@0: aoqi@0: { CodeletMark cm(_masm, "exception handling"); aoqi@0: // (Note: this is not safepoint safe because thread may return to compiled code) aoqi@0: generate_throw_exception(); aoqi@0: } aoqi@0: aoqi@0: { CodeletMark cm(_masm, "throw exception entrypoints"); aoqi@0: Interpreter::_throw_ArrayIndexOutOfBoundsException_entry = generate_ArrayIndexOutOfBounds_handler("java/lang/ArrayIndexOutOfBoundsException"); aoqi@0: Interpreter::_throw_ArrayStoreException_entry = generate_klass_exception_handler("java/lang/ArrayStoreException" ); aoqi@0: Interpreter::_throw_ArithmeticException_entry = generate_exception_handler("java/lang/ArithmeticException" , "/ by zero"); aoqi@0: Interpreter::_throw_ClassCastException_entry = generate_ClassCastException_handler(); aoqi@0: Interpreter::_throw_NullPointerException_entry = generate_exception_handler("java/lang/NullPointerException" , NULL ); aoqi@0: Interpreter::_throw_StackOverflowError_entry = generate_StackOverflowError_handler(); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: aoqi@0: #define method_entry(kind) \ aoqi@0: { CodeletMark cm(_masm, "method entry point (kind = " #kind ")"); \ aoqi@0: Interpreter::_entry_table[Interpreter::kind] = generate_method_entry(Interpreter::kind); \ aoqi@0: } aoqi@0: aoqi@0: // all non-native method kinds aoqi@0: method_entry(zerolocals) aoqi@0: method_entry(zerolocals_synchronized) aoqi@0: method_entry(empty) aoqi@0: method_entry(accessor) aoqi@0: method_entry(abstract) aoqi@0: method_entry(java_lang_math_sin ) aoqi@0: method_entry(java_lang_math_cos ) aoqi@0: method_entry(java_lang_math_tan ) aoqi@0: method_entry(java_lang_math_abs ) aoqi@0: method_entry(java_lang_math_sqrt ) aoqi@0: method_entry(java_lang_math_log ) aoqi@0: method_entry(java_lang_math_log10) aoqi@0: method_entry(java_lang_math_exp ) aoqi@0: method_entry(java_lang_math_pow ) aoqi@0: method_entry(java_lang_ref_reference_get) aoqi@0: aoqi@0: if (UseCRC32Intrinsics) { aoqi@0: method_entry(java_util_zip_CRC32_update) aoqi@0: method_entry(java_util_zip_CRC32_updateBytes) aoqi@0: method_entry(java_util_zip_CRC32_updateByteBuffer) aoqi@0: } aoqi@0: aoqi@0: initialize_method_handle_entries(); aoqi@0: aoqi@0: // all native method kinds (must be one contiguous block) aoqi@0: Interpreter::_native_entry_begin = Interpreter::code()->code_end(); aoqi@0: method_entry(native) aoqi@0: method_entry(native_synchronized) aoqi@0: Interpreter::_native_entry_end = Interpreter::code()->code_end(); aoqi@0: aoqi@0: #undef method_entry aoqi@0: aoqi@0: // Bytecodes aoqi@0: set_entry_points_for_all_bytes(); aoqi@0: set_safepoints_for_all_bytes(); aoqi@0: } aoqi@0: aoqi@0: //------------------------------------------------------------------------------------------------------------------------ aoqi@0: aoqi@0: address TemplateInterpreterGenerator::generate_error_exit(const char* msg) { aoqi@0: address entry = __ pc(); aoqi@0: __ stop(msg); aoqi@0: return entry; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: //------------------------------------------------------------------------------------------------------------------------ aoqi@0: aoqi@0: void TemplateInterpreterGenerator::set_entry_points_for_all_bytes() { aoqi@0: for (int i = 0; i < DispatchTable::length; i++) { aoqi@0: Bytecodes::Code code = (Bytecodes::Code)i; aoqi@0: if (Bytecodes::is_defined(code)) { aoqi@0: set_entry_points(code); aoqi@0: } else { aoqi@0: set_unimplemented(i); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void TemplateInterpreterGenerator::set_safepoints_for_all_bytes() { aoqi@0: for (int i = 0; i < DispatchTable::length; i++) { aoqi@0: Bytecodes::Code code = (Bytecodes::Code)i; aoqi@0: if (Bytecodes::is_defined(code)) Interpreter::_safept_table.set_entry(code, Interpreter::_safept_entry); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void TemplateInterpreterGenerator::set_unimplemented(int i) { aoqi@0: address e = _unimplemented_bytecode; aoqi@0: EntryPoint entry(e, e, e, e, e, e, e, e, e); aoqi@0: Interpreter::_normal_table.set_entry(i, entry); aoqi@0: Interpreter::_wentry_point[i] = _unimplemented_bytecode; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void TemplateInterpreterGenerator::set_entry_points(Bytecodes::Code code) { aoqi@0: CodeletMark cm(_masm, Bytecodes::name(code), code); aoqi@0: // initialize entry points aoqi@0: assert(_unimplemented_bytecode != NULL, "should have been generated before"); aoqi@0: assert(_illegal_bytecode_sequence != NULL, "should have been generated before"); aoqi@0: address bep = _illegal_bytecode_sequence; aoqi@0: address cep = _illegal_bytecode_sequence; aoqi@0: address sep = _illegal_bytecode_sequence; aoqi@0: address aep = _illegal_bytecode_sequence; aoqi@0: address iep = _illegal_bytecode_sequence; aoqi@0: address lep = _illegal_bytecode_sequence; aoqi@0: address fep = _illegal_bytecode_sequence; aoqi@0: address dep = _illegal_bytecode_sequence; aoqi@0: address vep = _unimplemented_bytecode; aoqi@0: address wep = _unimplemented_bytecode; aoqi@0: // code for short & wide version of bytecode aoqi@0: if (Bytecodes::is_defined(code)) { aoqi@0: Template* t = TemplateTable::template_for(code); aoqi@0: assert(t->is_valid(), "just checking"); aoqi@0: set_short_entry_points(t, bep, cep, sep, aep, iep, lep, fep, dep, vep); aoqi@0: } aoqi@0: if (Bytecodes::wide_is_defined(code)) { aoqi@0: Template* t = TemplateTable::template_for_wide(code); aoqi@0: assert(t->is_valid(), "just checking"); aoqi@0: set_wide_entry_point(t, wep); aoqi@0: } aoqi@0: // set entry points aoqi@0: EntryPoint entry(bep, cep, sep, aep, iep, lep, fep, dep, vep); aoqi@0: Interpreter::_normal_table.set_entry(code, entry); aoqi@0: Interpreter::_wentry_point[code] = wep; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void TemplateInterpreterGenerator::set_wide_entry_point(Template* t, address& wep) { aoqi@0: assert(t->is_valid(), "template must exist"); aoqi@0: assert(t->tos_in() == vtos, "only vtos tos_in supported for wide instructions"); aoqi@0: wep = __ pc(); generate_and_dispatch(t); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void TemplateInterpreterGenerator::set_short_entry_points(Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& vep) { aoqi@0: assert(t->is_valid(), "template must exist"); aoqi@0: switch (t->tos_in()) { aoqi@0: case btos: aoqi@0: case ctos: aoqi@0: case stos: aoqi@0: ShouldNotReachHere(); // btos/ctos/stos should use itos. aoqi@0: break; aoqi@0: case atos: vep = __ pc(); __ pop(atos); aep = __ pc(); generate_and_dispatch(t); break; aoqi@0: case itos: vep = __ pc(); __ pop(itos); iep = __ pc(); generate_and_dispatch(t); break; aoqi@0: case ltos: vep = __ pc(); __ pop(ltos); lep = __ pc(); generate_and_dispatch(t); break; aoqi@0: case ftos: vep = __ pc(); __ pop(ftos); fep = __ pc(); generate_and_dispatch(t); break; aoqi@0: case dtos: vep = __ pc(); __ pop(dtos); dep = __ pc(); generate_and_dispatch(t); break; aoqi@0: case vtos: set_vtos_entry_points(t, bep, cep, sep, aep, iep, lep, fep, dep, vep); break; aoqi@0: default : ShouldNotReachHere(); break; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: //------------------------------------------------------------------------------------------------------------------------ aoqi@0: aoqi@0: void TemplateInterpreterGenerator::generate_and_dispatch(Template* t, TosState tos_out) { aoqi@0: if (PrintBytecodeHistogram) histogram_bytecode(t); aoqi@0: #ifndef PRODUCT aoqi@0: // debugging code aoqi@0: if (CountBytecodes || TraceBytecodes || StopInterpreterAt > 0) count_bytecode(); aoqi@0: if (PrintBytecodePairHistogram) histogram_bytecode_pair(t); aoqi@0: if (TraceBytecodes) trace_bytecode(t); aoqi@0: if (StopInterpreterAt > 0) stop_interpreter_at(); aoqi@0: __ verify_FPU(1, t->tos_in()); aoqi@0: #endif // !PRODUCT aoqi@0: int step; aoqi@0: if (!t->does_dispatch()) { aoqi@0: step = t->is_wide() ? Bytecodes::wide_length_for(t->bytecode()) : Bytecodes::length_for(t->bytecode()); aoqi@0: if (tos_out == ilgl) tos_out = t->tos_out(); aoqi@0: // compute bytecode size aoqi@0: assert(step > 0, "just checkin'"); aoqi@0: // setup stuff for dispatching next bytecode aoqi@0: if (ProfileInterpreter && VerifyDataPointer aoqi@0: && MethodData::bytecode_has_profile(t->bytecode())) { aoqi@0: __ verify_method_data_pointer(); aoqi@0: } aoqi@0: __ dispatch_prolog(tos_out, step); aoqi@0: } aoqi@0: // generate template aoqi@0: t->generate(_masm); aoqi@0: // advance aoqi@0: if (t->does_dispatch()) { aoqi@0: #ifdef ASSERT aoqi@0: // make sure execution doesn't go beyond this point if code is broken aoqi@0: __ should_not_reach_here(); aoqi@0: #endif // ASSERT aoqi@0: } else { aoqi@0: // dispatch to next bytecode aoqi@0: __ dispatch_epilog(tos_out, step); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: //------------------------------------------------------------------------------------------------------------------------ aoqi@0: // Entry points aoqi@0: aoqi@0: /** aoqi@0: * Returns the return entry table for the given invoke bytecode. aoqi@0: */ aoqi@0: address* TemplateInterpreter::invoke_return_entry_table_for(Bytecodes::Code code) { aoqi@0: switch (code) { aoqi@0: case Bytecodes::_invokestatic: aoqi@0: case Bytecodes::_invokespecial: aoqi@0: case Bytecodes::_invokevirtual: aoqi@0: case Bytecodes::_invokehandle: aoqi@0: return Interpreter::invoke_return_entry_table(); aoqi@0: case Bytecodes::_invokeinterface: aoqi@0: return Interpreter::invokeinterface_return_entry_table(); aoqi@0: case Bytecodes::_invokedynamic: aoqi@0: return Interpreter::invokedynamic_return_entry_table(); aoqi@0: default: aoqi@0: fatal(err_msg("invalid bytecode: %s", Bytecodes::name(code))); aoqi@0: return NULL; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Returns the return entry address for the given top-of-stack state and bytecode. aoqi@0: */ aoqi@0: address TemplateInterpreter::return_entry(TosState state, int length, Bytecodes::Code code) { aoqi@0: guarantee(0 <= length && length < Interpreter::number_of_return_entries, "illegal length"); aoqi@0: const int index = TosState_as_index(state); aoqi@0: switch (code) { aoqi@0: case Bytecodes::_invokestatic: aoqi@0: case Bytecodes::_invokespecial: aoqi@0: case Bytecodes::_invokevirtual: aoqi@0: case Bytecodes::_invokehandle: aoqi@0: return _invoke_return_entry[index]; aoqi@0: case Bytecodes::_invokeinterface: aoqi@0: return _invokeinterface_return_entry[index]; aoqi@0: case Bytecodes::_invokedynamic: aoqi@0: return _invokedynamic_return_entry[index]; aoqi@0: default: aoqi@0: assert(!Bytecodes::is_invoke(code), err_msg("invoke instructions should be handled separately: %s", Bytecodes::name(code))); aoqi@0: return _return_entry[length].entry(state); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: address TemplateInterpreter::deopt_entry(TosState state, int length) { aoqi@0: guarantee(0 <= length && length < Interpreter::number_of_deopt_entries, "illegal length"); aoqi@0: return _deopt_entry[length].entry(state); aoqi@0: } aoqi@0: aoqi@0: //------------------------------------------------------------------------------------------------------------------------ aoqi@0: // Suport for invokes aoqi@0: aoqi@0: int TemplateInterpreter::TosState_as_index(TosState state) { aoqi@0: assert( state < number_of_states , "Invalid state in TosState_as_index"); aoqi@0: assert(0 <= (int)state && (int)state < TemplateInterpreter::number_of_return_addrs, "index out of bounds"); aoqi@0: return (int)state; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: //------------------------------------------------------------------------------------------------------------------------ aoqi@0: // Safepoint suppport aoqi@0: aoqi@0: static inline void copy_table(address* from, address* to, int size) { aoqi@0: // Copy non-overlapping tables. The copy has to occur word wise for MT safety. aoqi@0: while (size-- > 0) *to++ = *from++; aoqi@0: } aoqi@0: aoqi@0: void TemplateInterpreter::notice_safepoints() { aoqi@0: if (!_notice_safepoints) { aoqi@0: // switch to safepoint dispatch table aoqi@0: _notice_safepoints = true; aoqi@0: copy_table((address*)&_safept_table, (address*)&_active_table, sizeof(_active_table) / sizeof(address)); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // switch from the dispatch table which notices safepoints back to the aoqi@0: // normal dispatch table. So that we can notice single stepping points, aoqi@0: // keep the safepoint dispatch table if we are single stepping in JVMTI. aoqi@0: // Note that the should_post_single_step test is exactly as fast as the aoqi@0: // JvmtiExport::_enabled test and covers both cases. aoqi@0: void TemplateInterpreter::ignore_safepoints() { aoqi@0: if (_notice_safepoints) { aoqi@0: if (!JvmtiExport::should_post_single_step()) { aoqi@0: // switch to normal dispatch table aoqi@0: _notice_safepoints = false; aoqi@0: copy_table((address*)&_normal_table, (address*)&_active_table, sizeof(_active_table) / sizeof(address)); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: //------------------------------------------------------------------------------------------------------------------------ aoqi@0: // Deoptimization support aoqi@0: aoqi@0: // If deoptimization happens, this function returns the point of next bytecode to continue execution aoqi@0: address TemplateInterpreter::deopt_continue_after_entry(Method* method, address bcp, int callee_parameters, bool is_top_frame) { aoqi@0: return AbstractInterpreter::deopt_continue_after_entry(method, bcp, callee_parameters, is_top_frame); aoqi@0: } aoqi@0: aoqi@0: // If deoptimization happens, this function returns the point where the interpreter reexecutes aoqi@0: // the bytecode. aoqi@0: // Note: Bytecodes::_athrow (C1 only) and Bytecodes::_return are the special cases aoqi@0: // that do not return "Interpreter::deopt_entry(vtos, 0)" aoqi@0: address TemplateInterpreter::deopt_reexecute_entry(Method* method, address bcp) { aoqi@0: assert(method->contains(bcp), "just checkin'"); aoqi@0: Bytecodes::Code code = Bytecodes::java_code_at(method, bcp); aoqi@0: if (code == Bytecodes::_return) { aoqi@0: // This is used for deopt during registration of finalizers aoqi@0: // during Object.. We simply need to resume execution at aoqi@0: // the standard return vtos bytecode to pop the frame normally. aoqi@0: // reexecuting the real bytecode would cause double registration aoqi@0: // of the finalizable object. aoqi@0: return _normal_table.entry(Bytecodes::_return).entry(vtos); aoqi@0: } else { aoqi@0: return AbstractInterpreter::deopt_reexecute_entry(method, bcp); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // If deoptimization happens, the interpreter should reexecute this bytecode. aoqi@0: // This function mainly helps the compilers to set up the reexecute bit. aoqi@0: bool TemplateInterpreter::bytecode_should_reexecute(Bytecodes::Code code) { aoqi@0: if (code == Bytecodes::_return) { aoqi@0: //Yes, we consider Bytecodes::_return as a special case of reexecution aoqi@0: return true; aoqi@0: } else { aoqi@0: return AbstractInterpreter::bytecode_should_reexecute(code); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: #endif // !CC_INTERP