/* * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2022 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/
// Do an oop store like *(base + index) = val OR *(base + offset) = val // (only one of both variants is possible at the same time). // Index can be noreg. // Kills: // Rbase, Rtmp staticvoid do_oop_store(InterpreterMacroAssembler* _masm, Register base,
RegisterOrConstant offset, Register val, // Noreg means always null. Register tmp1, Register tmp2, Register tmp3,
DecoratorSet decorators) {
assert_different_registers(tmp1, tmp2, tmp3, val, base);
__ store_heap_oop(val, offset, base, tmp1, tmp2, tmp3, MacroAssembler::PRESERVATION_NONE, decorators);
}
Address TemplateTable::at_bcp(int offset) { // Not used on ppc.
ShouldNotReachHere(); return Address();
}
// Patches the current bytecode (ptr to it located in bcp) // in the bytecode stream with a new one. void TemplateTable::patch_bytecode(Bytecodes::Code new_bc, Register Rnew_bc, RegisterRtemp, bool load_bc_into_bc_reg /*=true*/, int byte_no) { // With sharing on, may need to test method flag. if (!RewriteBytecodes) return;
Label L_patch_done;
switch (new_bc) { case Bytecodes::_fast_aputfield: case Bytecodes::_fast_bputfield: case Bytecodes::_fast_zputfield: case Bytecodes::_fast_cputfield: case Bytecodes::_fast_dputfield: case Bytecodes::_fast_fputfield: case Bytecodes::_fast_iputfield: case Bytecodes::_fast_lputfield: case Bytecodes::_fast_sputfield:
{ // We skip bytecode quickening for putfield instructions when // the put_code written to the constant pool cache is zero. // This is required so that every execution of this instruction // calls out to InterpreterRuntime::resolve_get_put to do // additional, required work.
assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
assert(load_bc_into_bc_reg, "we use bc_reg as temp");
__ get_cache_and_index_at_bcp(Rtemp /* dst = cache */, 1); // ((*(cache+indices))>>((1+byte_no)*8))&0xFF: #ifdefined(VM_LITTLE_ENDIAN)
__ lbz(Rnew_bc, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()) + 1 + byte_no, Rtemp); #else
__ lbz(Rnew_bc, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()) + 7 - (1 + byte_no), Rtemp); #endif
__ cmpwi(CCR0, Rnew_bc, 0);
__ li(Rnew_bc, (unsignedint)(unsignedchar)new_bc);
__ beq(CCR0, L_patch_done); // __ isync(); // acquire not needed break;
}
// Resolved class - need to call vm to get java mirror of the class.
__ cmpwi(CCR1, Rscratch2, JVM_CONSTANT_Class);
__ crnor(CCR0, Assembler::equal, CCR1, Assembler::equal); // Neither resolved class nor unresolved case from above?
__ beq(CCR0, notClass);
// VMr = obj = base address to find primitive value to push // VMr2 = flags = (tos, off) using format of CPCE::_flags
__ andi(off, flags, ConstantPoolCacheEntry::field_index_mask);
// What sort of thing are we loading?
__ rldicl(flags, flags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits);
// Get the locals index located in the bytecode stream at bcp + offset. void TemplateTable::locals_index(Register Rdst, int offset) {
__ lbz(Rdst, offset, R14_bcp);
}
// get next byte
__ lbz(Rnext_byte, Bytecodes::length_for(Bytecodes::_iload), R14_bcp);
// if _iload, wait to rewrite to iload2. We only want to rewrite the // last two iloads in a pair. Comparing against fast_iload means that // the next bytecode is neither an iload or a caload, and therefore // an iload pair.
__ cmpwi(CCR0, Rnext_byte, (unsignedint)(unsignedchar)Bytecodes::_iload);
__ beq(CCR0, Ldone);
// Load a local variable type long from locals area to TOS cache register. // Local index resides in bytecodestream. void TemplateTable::lload() {
transition(vtos, ltos);
void TemplateTable::aload_0_internal(RewriteControl rc) {
transition(vtos, atos); // According to bytecode histograms, the pairs: // // _aload_0, _fast_igetfield // _aload_0, _fast_agetfield // _aload_0, _fast_fgetfield // // occur frequently. If RewriteFrequentPairs is set, the (slow) // _aload_0 bytecode checks if the next bytecode is either // _fast_igetfield, _fast_agetfield or _fast_fgetfield and then // rewrites the current bytecode into a pair bytecode; otherwise it // rewrites the current bytecode into _0 that doesn't do // the pair check anymore. // // Note: If the next bytecode is _getfield, the rewrite must be // delayed, otherwise we may miss an opportunity for a pair. // // Also rewrite frequent pairs // aload_0, aload_1 // aload_0, iload_1 // These bytecodes with a small amount of code are most profitable // to rewrite.
// Get next byte.
__ lbz(Rnext_byte, Bytecodes::length_for(Bytecodes::_aload_0), R14_bcp);
// If _getfield, wait to rewrite. We only want to rewrite the last two bytecodes in a pair.
__ cmpwi(CCR0, Rnext_byte, (unsignedint)(unsignedchar)Bytecodes::_getfield);
__ beq(CCR0, Ldont_rewrite);
__ ld(R17_tos, Interpreter::expr_offset_in_bytes(0), R15_esp); // Get value to store.
__ lwz(Rindex, Interpreter::expr_offset_in_bytes(1), R15_esp); // Get index.
__ ld(Rarray, Interpreter::expr_offset_in_bytes(2), R15_esp); // Get array.
// Do fast instanceof cache test.
__ ld(Rarray_element_klass, in_bytes(ObjArrayKlass::element_klass_offset()), Rarray_klass);
// Generate a fast subtype check. Branch to store_ok if no failure. Throw if failure.
__ gen_subtype_check(Rvalue_klass /*subklass*/, Rarray_element_klass /*superklass*/, Rscratch, Rscratch2, Rscratch3, Lstore_ok);
// Store is OK.
__ bind(Lstore_ok);
do_oop_store(_masm, Rstore_addr, arrayOopDesc::base_offset_in_bytes(T_OBJECT), R17_tos /* value */,
Rscratch, Rscratch2, Rscratch3, IS_ARRAY | IS_NOT_NULL);
__ bind(Ldone); // Adjust sp (pops array, index and value).
__ addi(R15_esp, R15_esp, 3 * Interpreter::stackElementSize);
}
// Need to check whether array is boolean or byte // since both types share the bastore bytecode.
__ load_klass(Rscratch, Rarray);
__ lwz(Rscratch, in_bytes(Klass::layout_helper_offset()), Rscratch); int diffbit = exact_log2(Klass::layout_helper_boolean_diffbit());
__ testbitdi(CCR0, R0, Rscratch, diffbit);
Label L_skip;
__ bfalse(CCR0, L_skip);
__ andi(R17_tos, R17_tos, 1); // if it is a T_BOOLEAN array, mask the stored value to 0/1
__ bind(L_skip);
Register Ra = R11_scratch1,
Rb = R12_scratch2,
Rc = R3_ARG1;
// stack: ..., a, b, c
__ ld(Rc, Interpreter::stackElementSize, R15_esp); // load c
__ ld(Ra, Interpreter::stackElementSize * 3, R15_esp); // load a
__ std(Rc, Interpreter::stackElementSize * 3, R15_esp); // store c in a
__ ld(Rb, Interpreter::stackElementSize * 2, R15_esp); // load b // stack: ..., c, b, c
__ std(Ra, Interpreter::stackElementSize * 2, R15_esp); // store a in b // stack: ..., c, a, c
__ std(Rb, Interpreter::stackElementSize, R15_esp); // store b in c
__ push_ptr(Rc); // push c // stack: ..., c, a, b, c
}
Register Ra = R11_scratch1,
Rb = R12_scratch2,
Rc = R3_ARG1,
Rd = R4_ARG2; // stack: ..., a, b, c, d
__ ld(Rb, Interpreter::stackElementSize * 3, R15_esp);
__ ld(Rd, Interpreter::stackElementSize, R15_esp);
__ std(Rb, Interpreter::stackElementSize, R15_esp); // store b in d
__ std(Rd, Interpreter::stackElementSize * 3, R15_esp); // store d in b
__ ld(Ra, Interpreter::stackElementSize * 4, R15_esp);
__ ld(Rc, Interpreter::stackElementSize * 2, R15_esp);
__ std(Ra, Interpreter::stackElementSize * 2, R15_esp); // store a in c
__ std(Rc, Interpreter::stackElementSize * 4, R15_esp); // store c in a // stack: ..., c, d, a, b
__ push_2ptrs(Rc, Rd); // stack: ..., c, d, a, b, c, d
}
void TemplateTable::swap() {
transition(vtos, vtos); // stack: ..., a, b
Register Ra = R11_scratch1,
Rb = R12_scratch2; // stack: ..., a, b
__ ld(Rb, Interpreter::stackElementSize, R15_esp);
__ ld(Ra, Interpreter::stackElementSize * 2, R15_esp);
__ std(Rb, Interpreter::stackElementSize * 2, R15_esp);
__ std(Ra, Interpreter::stackElementSize, R15_esp); // stack: ..., b, a
}
void TemplateTable::convert() { // %%%%% Factor this first part across platforms #ifdef ASSERT
TosState tos_in = ilgl;
TosState tos_out = ilgl; switch (bytecode()) { case Bytecodes::_i2l: // fall through case Bytecodes::_i2f: // fall through case Bytecodes::_i2d: // fall through case Bytecodes::_i2b: // fall through case Bytecodes::_i2c: // fall through case Bytecodes::_i2s: tos_in = itos; break; case Bytecodes::_l2i: // fall through case Bytecodes::_l2f: // fall through case Bytecodes::_l2d: tos_in = ltos; break; case Bytecodes::_f2i: // fall through case Bytecodes::_f2l: // fall through case Bytecodes::_f2d: tos_in = ftos; break; case Bytecodes::_d2i: // fall through case Bytecodes::_d2l: // fall through case Bytecodes::_d2f: tos_in = dtos; break; default : ShouldNotReachHere();
} switch (bytecode()) { case Bytecodes::_l2i: // fall through case Bytecodes::_f2i: // fall through case Bytecodes::_d2i: // fall through case Bytecodes::_i2b: // fall through case Bytecodes::_i2c: // fall through case Bytecodes::_i2s: tos_out = itos; break; case Bytecodes::_i2l: // fall through case Bytecodes::_f2l: // fall through case Bytecodes::_d2l: tos_out = ltos; break; case Bytecodes::_i2f: // fall through case Bytecodes::_l2f: // fall through case Bytecodes::_d2f: tos_out = ftos; break; case Bytecodes::_i2d: // fall through case Bytecodes::_l2d: // fall through case Bytecodes::_f2d: tos_out = dtos; break; default : ShouldNotReachHere();
}
transition(tos_in, tos_out); #endif
case Bytecodes::_l2i: // Nothing to do, we'll continue to work with the lower bits. break;
case Bytecodes::_i2b:
__ extsb(R17_tos, R17_tos); break;
case Bytecodes::_i2c:
__ rldicl(R17_tos, R17_tos, 0, 64-2*8); break;
case Bytecodes::_i2s:
__ extsh(R17_tos, R17_tos); break;
case Bytecodes::_i2d:
__ extsw(R17_tos, R17_tos); case Bytecodes::_l2d:
__ move_l_to_d();
__ fcfid(F15_ftos, F15_ftos); break;
case Bytecodes::_i2f:
__ extsw(R17_tos, R17_tos);
__ move_l_to_d(); if (VM_Version::has_fcfids()) { // fcfids is >= Power7 only // Comment: alternatively, load with sign extend could be done by lfiwax.
__ fcfids(F15_ftos, F15_ftos);
} else {
__ fcfid(F15_ftos, F15_ftos);
__ frsp(F15_ftos, F15_ftos);
} break;
case Bytecodes::_l2f: if (VM_Version::has_fcfids()) { // fcfids is >= Power7 only
__ move_l_to_d();
__ fcfids(F15_ftos, F15_ftos);
} else { // Avoid rounding problem when result should be 0x3f800001: need fixup code before fcfid+frsp.
__ mr(R3_ARG1, R17_tos);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::l2f));
__ fmr(F15_ftos, F1_RET);
} break;
case Bytecodes::_f2d: // empty break;
case Bytecodes::_d2f:
__ frsp(F15_ftos, F15_ftos); break;
case Bytecodes::_d2i: case Bytecodes::_f2i:
__ fcmpu(CCR0, F15_ftos, F15_ftos);
__ li(R17_tos, 0); // 0 in case of NAN
__ bso(CCR0, done);
__ fctiwz(F15_ftos, F15_ftos);
__ move_d_to_l(); break;
case Bytecodes::_d2l: case Bytecodes::_f2l:
__ fcmpu(CCR0, F15_ftos, F15_ftos);
__ li(R17_tos, 0); // 0 in case of NAN
__ bso(CCR0, done);
__ fctidz(F15_ftos, F15_ftos);
__ move_d_to_l(); break;
default: ShouldNotReachHere();
}
__ bind(done);
}
// Long compare void TemplateTable::lcmp() {
transition(ltos, itos);
constRegister Rscratch = R11_scratch1;
__ pop_l(Rscratch); // first operand, deeper in stack
__ cmpd(CCR0, Rscratch, R17_tos); // compare
__ set_cmp3(R17_tos); // set result as follows: <: -1, =: 0, >: 1
}
// fcmpl/fcmpg and dcmpl/dcmpg bytecodes // unordered_result == -1 => fcmpl or dcmpl // unordered_result == 1 => fcmpg or dcmpg void TemplateTable::float_cmp(bool is_float, int unordered_result) { const FloatRegister Rfirst = F0_SCRATCH,
Rsecond = F15_ftos; constRegister Rscratch = R11_scratch1;
// If no method data exists, go to profile_continue.
__ ld(Rmdo, in_bytes(Method::method_data_offset()), R19_method);
__ cmpdi(CCR0, Rmdo, 0);
__ beq(CCR0, Lno_mdo);
// Helper function for if_cmp* methods below. // Factored out common compare and branch code. void TemplateTable::if_cmp_common(Register Rfirst, Register Rsecond, Register Rscratch1, Register Rscratch2, Condition cc, bool is_jint, bool cmp0) {
Label Lnot_taken; // Note: The condition code we get is the condition under which we // *fall through*! So we have to inverse the CC here.
// Conition is false => Jump!
branch(false, false);
// Condition is not true => Continue.
__ align(32, 12);
__ bind(Lnot_taken);
__ profile_not_taken_branch(Rscratch1, Rscratch2);
}
// Compare integer values with zero and fall through if CC holds, branch away otherwise. void TemplateTable::if_0cmp(Condition cc) {
transition(itos, vtos);
// Table switch using binary search (value/offset pairs are ordered). // Bytecode stream format: // Bytecode (1) | 4-byte padding | default offset (4) | count (4) | value/offset pair1 (8) | value/offset pair2 (8) | ... // Note: Everything is big-endian format here. So on little endian machines, we have to revers offset and count and cmp value. void TemplateTable::fast_binaryswitch() {
transition(itos, vtos); // Implementation using the following core algorithm: (copied from Intel) // // int binary_search(int key, LookupswitchPair* array, int n) { // // Binary search according to "Methodik des Programmierens" by // // Edsger W. Dijkstra and W.H.J. Feijen, Addison Wesley Germany 1985. // int i = 0; // int j = n; // while (i+1 < j) { // // invariant P: 0 <= i < j <= n and (a[i] <= key < a[j] or Q) // // with Q: for all i: 0 <= i < n: key < a[i] // // where a stands for the array and assuming that the (inexisting) // // element a[n] is infinitely big. // int h = (i + j) >> 1; // // i < h < j // if (key < array[h].fast_match()) { // j = h; // } else { // i = h; // } // } // // R: a[i] <= key < a[i+1] or Q // // (i.e., if key is within array, i is the correct index) // return i; // }
// while (i+1 < j)
__ bind(entry);
__ addi(Rscratch, Ri, 1);
__ cmpw(CCR0, Rscratch, Rj);
__ add(Rh, Ri, Rj); // start h = i + j >> 1;
__ blt(CCR0, loop);
}
// End of binary search, result index is i (must check again!).
Label default_case;
Label continue_execution; if (ProfileInterpreter) {
__ mr(Rh, Ri); // Save index in i for profiling.
} // Ri = value offset
__ sldi(Ri, Ri, log_entry_size);
__ add(Ri, Ri, Rarray);
__ get_u4(Rscratch, Ri, 0, InterpreterMacroAssembler::Unsigned);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.