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; }