SExpr* SPrimScope::inlineIntArithmetic() { ArithOpCode op = opcode_for_selector(_selector); bool intRcvr = receiver->hasMap() && receiver->map() == Memory->smi_map; SExpr* arg = args->nth(0); bool intArg = arg->hasMap() && arg->map() == Memory->smi_map; if ( intArg && arg->isConstantSExpr() && intRcvr && arg->constant() == as_smiOop(0) && can_fold_rcvr_op_zero_to_zero(op)) { if (PrintInlining) lprintf("%*s*constant-folding %s: 0\n", (void*)(depth-1), "", ArithOpName[op]); return receiver; } if (PrintInlining) lprintf("%*s*inlining %s:\n", (void*)(depth-1), "", ArithOpName[op]); if (!TArithRRNode::isOpInlinable(op)) return NULL; NodeGen* n = theNodeGen; Node* arith = n->append(new TArithRRNode(op, receiver->preg(), arg->preg(), resultPR, intRcvr, intArg)); // success case - no overflow, int tags MergeNode* ok = (MergeNode*)n->append(new MergeNode("inlineIntArithmetic ok")); SExpr* succExpr = new MapSExpr(Memory->smi_map->enclosing_mapOop(), resultPR, ok); // merge of success & failure branches MergeNode* done = (MergeNode*)ok->append(new MergeNode("inlineIntArithmetic done")); // failure case n->current = arith->append1(new NopNode); if (theSIC->useUncommonTraps && sender()->rscope->isUncommonAt(sender()->bci(), true)) { n->uncommonBranch(currentExprStack(0), true); n->current = done; if (PrintInlining) { lprintf("%*s*making arithmetic failure uncommon\n", (void*)(depth-1), ""); } return succExpr; } else { fint b = bci(); PReg* error = new SAPReg(_sender, b, b); if (intRcvr && intArg) { // must be overflow n->loadOop(VMString[OVERFLOWERROR], error); } else { arith->hasSideEffects_now = true; // may fail, so can't eliminate if (intRcvr || TARGET_ARCH == I386_ARCH) { // arg & TagMask already done by TArithRRNode // I386 does 'em all } else { PReg* t = new TempPReg(this, Temp1, false, true); n->append(new ArithRCNode(AndCCArithOp, t, Tag_Mask, t)); n->current->hasSideEffects_now = true; } // Note: this code assumes that condcode EQ means overflow Node* branch = n->append(new BranchNode(EQBranchOp)); // no overflow, must be type error n->loadOop(VMString[BADTYPEERROR], error); MergeNode* cont = (MergeNode*)n->append( new MergeNode("inlineIntArithmetic cont")); // overflow error PReg* err = new_ConstPReg(_sender, VMString[OVERFLOWERROR]); n->current = branch->append1(new AssignNode(err, error)); n->branch(cont); } Node* dummy; SExpr* failExpr = genPrimFailure(NULL, error, dummy, done, resultPR); assert(done, "merge should always exist"); return succExpr->mergeWith(failExpr, done); } }
SExpr* SPrimScope::inlineAtPut(bool objVector) { assert(_selector == VMString[objVector ? _AT_PUT_ : _BYTE_AT_PUT_], "bad selector"); bool okRcvr = receiver->hasMap(); Map* rm; if (okRcvr) { rm = receiver->map(); if (objVector) { okRcvr = rm->is_objVector(); } else { okRcvr = rm->is_byteVector(); } } if (!okRcvr) { // receiver type not known statically return NULL; } if (PrintInlining) lprintf("%*s*inlining _%sAtPut:\n", (void*)(depth-1), "", objVector ? "" :"Byte"); SExpr* arg = args->nth(1); NodeGen* ng = theNodeGen; if (SICDebug) ng->comment("inlined _At:Put:/_ByteAt:Put:"); fint b = bci(); bool intArg = arg->hasMap() && arg->map() == Memory->smi_map; bool willFail = arg->hasMap() && arg->map() != Memory->smi_map; bool useUncommonTrap = !willFail && theSIC->useUncommonTraps && sender()->rscope->isUncommonAt(sender()->bci(), true); PReg* errorPR = useUncommonTrap ? NULL : new SAPReg(_sender, b, b); Node* at; if (objVector) { PReg* elementArgPR = args->nth(0)->preg(); // materialize value arg theNodeGen->materializeBlock(elementArgPR, _sender->sig, new PRegBList(1)); fint size = ((slotsMap*)rm)->empty_vector_object_size(); at = new ArrayAtPutNode(receiver->preg(), arg->preg(), intArg, elementArgPR, resultPR, errorPR, size * oopSize - Mem_Tag); } else { SExpr* value = args->nth(0); bool intVal = value->hasMap() && value->map() == Memory->smi_map; willFail |= value->hasMap() && value->map() != Memory->smi_map; at = new ByteArrayAtPutNode(receiver->preg(), arg->preg(), intArg, value->preg(), intVal, resultPR, errorPR); } ng->append(at); // success case - int index, in bounds MergeNode* ok = (MergeNode*)ng->append(new NopNode); // merge of success & failure branches MergeNode* done = (MergeNode*)ok->append(new MergeNode("inlineAtPut done")); // failure case SExpr* res = receiver->shallowCopy(resultPR, ok); ng->current = at->append1(new MergeNode("inlineAtPut current")); if (useUncommonTrap) { if (PrintInlining) { lprintf("%*s*making atPut: failure uncommon\n", (void*)(depth-1), ""); } ng->uncommonBranch(currentExprStack(0), true); ng->current = done; } else { Node* dummy; SExpr* failExpr = genPrimFailure(NULL, errorPR, dummy, done, resultPR); assert(done, "node should always exist"); res = res->mergeWith(failExpr, done); } return res; }
Expr* PrimInliner::smi_ArithmeticOp(ArithOpCode op, Expr* arg1, Expr* arg2) { assert_failure_block(); assert_receiver(); // parameters & result registers bool intArg1 = arg1->is_smi(); bool intArg2 = arg2->is_smi(); bool intBoth = intArg1 && intArg2; // if true, tag error cannot occur SAPReg* resPReg = new SAPReg(_scope); // holds the result if primitive didn't fail SAPReg* errPReg = new SAPReg(_scope); // holds the error message if primitive failed MergeNode* failureStart = NodeFactory::new_MergeNode(_failure_block->begin_bci()); // n1: operation & treatment of tag error Node* n1; AssignNode* n1Err; ConstantExpr* n1Expr = NULL; if (intBoth) { // tag error cannot occur n1 = NodeFactory::new_ArithRRNode(resPReg, arg1->preg(), op, arg2->preg()); } else { // tag error can occur n1 = NodeFactory::new_TArithRRNode(resPReg, arg1->preg(), op, arg2->preg(), intArg1, intArg2); if (shouldUseUncommonTrap()) { // simply jump to uncommon branch code n1->append(1, failureStart); } else { ConstPReg* n1PReg = new_ConstPReg(_scope, vmSymbols::first_argument_has_wrong_type()); n1Err = NodeFactory::new_AssignNode(n1PReg, errPReg); n1Expr = new ConstantExpr(n1PReg->constant, errPReg, n1Err); n1->append(1, n1Err); n1Err->append(failureStart); } } _gen->append(n1); Expr* result = new KlassExpr(smiKlassObj, resPReg, n1); // n2: overflow check & treatment of overflow const bool taken_is_uncommon = true; BranchNode* n2 = NodeFactory::new_BranchNode(VSBranchOp, taken_is_uncommon); AssignNode* n2Err; ConstantExpr* n2Expr = NULL; if (shouldUseUncommonTrap()) { // simply jump to uncommon branch code n2->append(1, failureStart); } else { ConstPReg* n2PReg = new_ConstPReg(_scope, vmSymbols::smi_overflow()); n2Err = NodeFactory::new_AssignNode(n2PReg, errPReg); n2Expr = new ConstantExpr(n2PReg->constant, errPReg, n2Err); n2->append(1, n2Err); n2Err->append(failureStart); } _gen->append(n2); // continuation if (shouldUseUncommonTrap()) { // uncommon branch instead of failure code failureStart->append(NodeFactory::new_UncommonNode(_gen->copyCurrentExprStack(), _bci /*_failure_block->begin_bci()*/)); } else { assert(n2Expr != NULL, "no error message defined"); Expr* error; if (n1Expr != NULL) { error = new MergeExpr(n1Expr, n2Expr, errPReg, failureStart); } else { error = n2Expr; } result = merge_failure_block(n2, result, failureStart, error, false); } return result; }