static bool match(UnsafeRawOp* x, Instruction** base, Instruction** index, int* log2_scale) { Instruction* instr_to_unpin = NULL; ArithmeticOp* root = x->base()->as_ArithmeticOp(); if (root == NULL) return false; // Limit ourselves to addition for now if (root->op() != Bytecodes::_ladd) return false; // Try to find shift or scale op if (match_index_and_scale(root->y(), index, log2_scale, &instr_to_unpin)) { *base = root->x(); } else if (match_index_and_scale(root->x(), index, log2_scale, &instr_to_unpin)) { *base = root->y(); } else if (root->y()->as_Convert() != NULL) { Convert* convert = root->y()->as_Convert(); if (convert->op() == Bytecodes::_i2l && convert->value()->type() == intType) { // pick base and index, setting scale at 1 *base = root->x(); *index = convert->value(); *log2_scale = 0; } else { return false; } } else { // doesn't match any expected sequences return false; } // Typically the addition is pinned, as it is the result of an // inlined routine. We want to unpin it so as to avoid the long // addition, but in order to do so we must still ensure that the // operands are pinned, as they may be computed arbitrarily before // the Unsafe op completes (even if the Unsafe op is pinned). At // this point we do not really need to pin Unsafe raw or object // gets. if (root->is_pinned()) { if (root->pin_state() == Instruction::PinInlineReturnValue) { assert(x->is_pinned(), "All unsafe raw ops should be pinned"); root->unpin(Instruction::PinInlineReturnValue); (*base)->pin(); (*index)->pin(); } else { // can't safely unpin this instruction return false; } } if (PrintUnsafeOptimization && instr_to_unpin != NULL) { tty->print_cr("pin_state = 0x%x", instr_to_unpin->pin_state()); instr_to_unpin->print(); } return true; }
static bool match_index_and_scale(Instruction* instr, Instruction** index, int* log2_scale, Instruction** instr_to_unpin) { *instr_to_unpin = NULL; // Skip conversion ops Convert* convert = instr->as_Convert(); if (convert != NULL) { instr = convert->value(); } ShiftOp* shift = instr->as_ShiftOp(); if (shift != NULL) { if (shift->is_pinned()) { *instr_to_unpin = shift; } // Constant shift value? Constant* con = shift->y()->as_Constant(); if (con == NULL) return false; // Well-known type and value? IntConstant* val = con->type()->as_IntConstant(); if (val == NULL) return false; if (shift->x()->type() != intType) return false; *index = shift->x(); int tmp_scale = val->value(); if (tmp_scale >= 0 && tmp_scale < 4) { *log2_scale = tmp_scale; return true; } else { return false; } } ArithmeticOp* arith = instr->as_ArithmeticOp(); if (arith != NULL) { if (arith->is_pinned()) { *instr_to_unpin = arith; } // Check for integer multiply if (arith->op() == Bytecodes::_imul) { // See if either arg is a known constant Constant* con = arith->x()->as_Constant(); if (con != NULL) { *index = arith->y(); } else { con = arith->y()->as_Constant(); if (con == NULL) return false; *index = arith->x(); } if ((*index)->type() != intType) return false; // Well-known type and value? IntConstant* val = con->type()->as_IntConstant(); if (val == NULL) return false; switch (val->value()) { case 1: *log2_scale = 0; return true; case 2: *log2_scale = 1; return true; case 4: *log2_scale = 2; return true; case 8: *log2_scale = 3; return true; default: return false; } } } // Unknown instruction sequence; don't touch it return false; }
// Here we set all the flags void ScanBlocks::scan_block(BlockBegin* block, ScanResult* desc, bool live_only) { for (Instruction* n = block; n != NULL; n = n->next()) { if (live_only && !n->is_pinned() && (n->use_count() == 0)) { // don't look at unused instructions because no code is emitted for them continue; } ValueTag tag = n->type()->tag(); if (tag == floatTag) desc->set_has_floats(true); else if (tag == doubleTag) desc->set_has_doubles(true); if (n->as_StateSplit() != NULL) { if (n->as_Invoke() != NULL) { desc->set_has_calls(true); } else if (n->as_NewArray() || n->as_NewInstance() || n->as_AccessMonitor()) { desc->set_has_slow_cases(true); } else if(n->as_Intrinsic() != NULL) { Intrinsic* i = n->as_Intrinsic(); if (i->id() == methodOopDesc::_arraycopy) desc->set_has_slow_cases(true); if (!i->preserves_state()) desc->set_has_calls(true); } } else if (n->as_AccessField() != NULL) { AccessField* af = n->as_AccessField(); if (!af->is_initialized() || !af->is_loaded()) desc->set_has_class_init(true); } else if (n->as_AccessLocal() != NULL) { AccessLocal* local = n->as_AccessLocal(); StoreLocal* store = n->as_StoreLocal(); int use_count = 0; if (store != NULL) { if (!store->is_eliminated()) { use_count = 1; } } else { use_count = n->use_count(); } if (use_count > 0) { ValueType* type = local->type(); assert(local->has_offset(), "must have had offset allocated"); accumulate_access(in_words(local->offset()), tag, use_count); } } #ifdef SPARC else { if (n->as_Convert() != NULL) { Convert* conv = n->as_Convert(); switch (conv->op()) { case Bytecodes::_l2f: case Bytecodes::_l2d: case Bytecodes::_f2l: case Bytecodes::_d2l: case Bytecodes::_d2i: { desc->set_has_calls(true); break; } } } else if (n->as_ArithmeticOp() != NULL) { ArithmeticOp* arith = n->as_ArithmeticOp(); switch (arith->op()) { case Bytecodes::_lrem: case Bytecodes::_ldiv: case Bytecodes::_lmul: case Bytecodes::_drem: case Bytecodes::_frem: { desc->set_has_calls(true); break; } } } } #endif } }