Esempio n. 1
0
 lookupTarget* sicScopeLookupTarget::get_target_for_slot(slotDesc* s,
                                                         simpleLookup* L) {
   Unused(L);
   if (s->name == VMString[LEXICAL_PARENT]) {
     return new sicScopeLookupTarget(scope->parent());
   } else if (s->name == VMString[SELF]) {
     SExpr* t = scope->receiverExpr();
     if (t->isConstantSExpr()) {
       return (new objectLookupTarget(t->constant())) -> be_receiver();
     } else if (t->hasMap()) {
       return ( new mapLookupTarget(t->map())) -> be_receiver();
     } else {
       // don't know the receiver type
       return NULL;
     }
   } else if (! s->is_map_slot()) {
     return NULL;
   } else {
     return new objectLookupTarget(s->data);
   }
 }
Esempio n. 2
0
  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;
  }
Esempio n. 3
0
  SExpr* SPrimScope::inlineAt(bool objVector) {
    assert(_selector == VMString[objVector ? _AT_ : _BYTE_AT_],
           "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 %s\n", (void*)(depth-1), "",
              objVector ? "_At:" : "_ByteAt:");
    
    SExpr* arg = args->nth(0);
    NodeGen* ng = theNodeGen;
    if (SICDebug) ng->comment("inlined _At:/_ByteAt:");
    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);
    // optimization: don't set error reg if using uncommon trap
    // (primitive will be reexecuted anyway)
    PReg* errorPR = useUncommonTrap ? NULL : new SAPReg(_sender, b, b);
    Node* at;
    if (objVector) {
      fint size = ((slotsMap*)rm)->empty_vector_object_size();
      at = new ArrayAtNode(receiver->preg(), arg->preg(), intArg,
                           resultPR, errorPR, size * oopSize - Mem_Tag);
                           
    } else {
      at = new ByteArrayAtNode(receiver->preg(), arg->preg(), intArg,
                               resultPR, errorPR);
    }
    ng->append(at);
    
    // success case - int index, in bounds
    NopNode* ok = (NopNode*)ng->append(new NopNode);
    // merge of success & failure branches
    MergeNode* done = (MergeNode*)ok->append(new MergeNode("inlineAt done"));

    // failure case
    ng->current = at->append1(new NopNode);
    if (useUncommonTrap) {
      if (PrintInlining) {
        lprintf("%*s*making at: 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, "merge should exist");
    }
    return new UnknownSExpr(resultPR, ok);
  }
Esempio n. 4
0
  SExpr* SPrimScope::inlineIntComparison() {
    BranchOpCode cond;
           if (_selector == VMString[_INT_EQ_]) {
      cond = EQBranchOp;
    } else if (_selector == VMString[_INT_LT_]) {
      cond = LTBranchOp;
    } else if (_selector == VMString[_INT_LE_]) {
      cond = LEBranchOp;
    } else if (_selector == VMString[_INT_GT_]) {
      cond = GTBranchOp;
    } else if (_selector == VMString[_INT_GE_]) {
      cond = GEBranchOp;
    } else if (_selector == VMString[_INT_NE_]) {
      cond = NEBranchOp;
    } else {
      return NULL;
    }

    bool intRcvr =
      receiver->hasMap() && receiver->map() == Memory->smi_map;
    SExpr* arg = args->nth(0);
    bool intArg = arg->hasMap() && arg->map() == Memory->smi_map;
    if (PrintInlining)
      lprintf("%*s*inlining int comparison prim\n", (void*)(depth-1), "");

    NodeGen* n = theNodeGen;
    Node* branch = n->append(new TBranchNode(cond, receiver->preg(), intRcvr,
                                             arg->preg(), intArg));

    // false branch
    n->move(falsePR(), resultPR);
    SExpr* falseExpr= new ConstantSExpr(Memory->falseObj, resultPR, n->current);
    MergeNode* done = (MergeNode*)n->append(
      new MergeNode("inlineIntComparison done"));

    // true branch
    n->current = branch->append1(new AssignNode(truePR(), resultPR));
    SExpr* trueExpr = new ConstantSExpr(Memory->trueObj, resultPR, n->current);
    n->branch(done);

    SExpr* res = trueExpr->copyMergeWith(falseExpr, resultPR, done);
    // failure branch
    if (!intRcvr || !intArg) {
      branch->hasSideEffects_now = true;
      if (theSIC->useUncommonTraps &&
          sender()->rscope->isUncommonAt(sender()->bci(), true)) {
        n->current = branch->append(2, new NopNode);
        n->uncommonBranch(currentExprStack(0), true);
        n->current = done;
        if (PrintInlining) {
          lprintf("%*s*making int comparison failure uncommon\n",
                  (void*)(depth-1), "");
        }
      } else {
        fint b = bci();
        PReg* error = new SAPReg(_sender, b, b);
        PReg* err = new_ConstPReg(_sender, VMString[BADTYPEERROR]);
        n->current = branch->append(2, new AssignNode(err, error));
        Node* dummy;
        SExpr* failExpr = genPrimFailure(NULL, error, dummy, done, resultPR);
        assert(done, "merge should always exist");
        res = (MergeSExpr*)res->mergeWith(failExpr, done);
      }
    }
    return res;
  }
Esempio n. 5
0
  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);
    }
  }
Esempio n. 6
0
  SExpr* SCodeScope::inlineMerge(SendInfo* info, MergeNode*& merge) {
    // inline the send by type-casing; return uninlined cases in others list
    // If merge has no predecessors, return NULL for merge ref.
    SExpr* res = NULL;
    assert(info->rcvr->isMergeSExpr(), "must be a merge");
    MergeSExpr* r = (MergeSExpr*)info->rcvr;
    stringOop sel = info->sel;
    merge = NULL;

    if (r->isSplittable() && shouldSplit(info)) {
      return splitMerge(info, merge);
    }
                    
    fint ncases = r->exprs->length();
    if (ncases > SICTypeCaseLimit) {
      info->needRealSend = true;
      if (PrintInlining) {
        lprintf("%*s*not type-casing %s (%ld > SICTypeCaseLimit)\n",
                (void*)depth, "", selector_string(sel), (void*)ncases);
      }
      return res;
    }
    assert( merge == NULL, "I assume merge is out param only");
    merge = new MergeNode("inlineMerge merge");

    if (SICDebug) {
      char* s = NEW_RESOURCE_ARRAY(char, 200);
      sprintf(s, "begin type-case of %s (ends at node N%ld)",
              sel->copy_null_terminated(), long(merge->id()));
      theNodeGen->comment(s);
    }
    if (PrintInlining) {
      lprintf("%*s*type-casing %s\n", (void*)depth, "", selector_string(sel));
    }

    // build list of cases to inline
    // (add only immediate maps at first, collect others in ...2 lists
    SSelfScopeBList* slist  = new SSelfScopeBList(ncases);
    SSelfScopeBList* slist2 = new SSelfScopeBList(ncases);
    SExprBList* elist  = new SExprBList(ncases);
    SExprBList* elist2 = new SExprBList(ncases);
    SExprBList* others = new SExprBList(ncases);
    OopBList* mlist  = new OopBList(ncases);
    OopBList* mlist2 = new OopBList(ncases);
    bool needMapLoad = false;
    fint i;
    for (i = 0; i < ncases; i++) {    
      SExpr* nth = r->exprs->nth(i);
      assert(!nth->isConstantSExpr() || nth->next == NULL ||
             nth->constant() == nth->next->constant(),
             "shouldn't happen: merged consts - convert to map");
      SSelfScope* s;

      if (!nth->hasMap()  ||  (s = tryLookup(info, nth)) == NULL) {
        // cannot inline
        others->append(nth);
        info->needRealSend = true;
        continue;
      }
      // can inline this case

      // Notice that for immediates, instead of putting the constants in the mlist,
      // we put the maps. No point in optimizing just for 17. -- dmu 6/05
      Map* map = nth->map();
      if (map == Memory->smi_map  ||  map == Memory->float_map) {
        slist ->append(s);        // immediate maps go first
        // Bug fix: instead of nth->shallowCopy, must generalize to any 
        // with same map, not just the same constant, because other ints (for example)
        // will pass the type test, too. -- dmu 6/05
        elist ->append(new MapSExpr(map->enclosing_mapOop(), r->preg(), NULL));
        mlist ->append(map->enclosing_mapOop());
        continue;
      }
      // can inline but not immediate map
      slist2->append(s);        // append later
      elist2->append(nth->shallowCopy(r->preg(), NULL)); // use preg of merge
      if (nth->isConstantSExpr()) {
        mlist2->append(nth->constant());
      }
      else {
        needMapLoad = true; // will need to load map of testee
        mlist2->append(map->enclosing_mapOop());
      }
    }

    mlist->appendList(mlist2);
    elist->appendList(elist2);
    slist->appendList(slist2);
        
    // now do the type test and inline the individual cases
    if (slist->length() > 0) {
      memoizeBlocks(sel);
      
      Node* typeCase =
        theNodeGen->append(new TypeTestNode(r->preg(), mlist, needMapLoad,
                                            info->needRealSend));
      Node* fallThrough = typeCase->append(new NopNode);
      for (i = 0; i < slist->length(); i++) {
        theNodeGen->current = typeCase->append(i + 1, new NopNode);
        SExpr* e = doInline(slist->nth(i), elist->nth(i), theNodeGen->current, merge);
        if (!e->isNoResultSExpr()) {
          theNodeGen->append(new NopNode);
          e = e->shallowCopy(info->resReg, theNodeGen->current);
          res = res ? res->mergeWith(e, merge) : e;
        }
        theNodeGen->branch(merge);
      }
      theNodeGen->current = fallThrough;
    }
    if (res && res->isMergeSExpr()) 
      res->setNode(merge, info->resReg);
      
    assert( info->needRealSend &&  others->length() ||
           !info->needRealSend && !others->length(), "inconsistent");
           
    // NB: *must* use uncommon branch if marked unlikely because
    // future type tests won't test for unknown
                      
    if (others->isEmpty()) {
      // typecase cannot fail
      theNodeGen->deadEnd();
    }
    else if ( others->length() == 1
         &&   others->first()->isUnknownSExpr()
         &&   ((UnknownSExpr*)others->first())->isUnlikely()) {
            // generate an uncommon branch for the unknown case, not a send
            theNodeGen->uncommonBranch(currentExprStack(0), info->restartPrim);
            info->needRealSend = false;
            if (PrintInlining)
              lprintf("%*s*making %s uncommon (2)\n", (void*)depth,"",selector_string(sel));
    }
    return res;
  }
Esempio n. 7
0
 SExpr* SCodeScope::typePredict(SendInfo* info) {
   // try static type prediction
   PReg* r = info->rcvr->preg();
   stringOop sel = info->sel;
   if (sel == VMString[IF_TRUE_] ||
       sel == VMString[IF_FALSE_] ||
       sel == VMString[IF_TRUE_FALSE_] ||
       sel == VMString[IF_FALSE_TRUE_] ||
       sel == VMString[OR]  || sel == VMString[AND] || sel == VMString[NOT]) {
     // boolean message
     if (PrintInlining) {
       lprintf("%*s*type-predicting %s\n", (void*)depth, "",
              sel->copy_null_terminated());
     }
     info->predicted = true;
     bool allowUnlikely = theSIC->useUncommonTraps;
     if (SICDeferUncommonBranches &&
         (sel == VMString[IF_TRUE_] ||
          sel == VMString[IF_FALSE_] ||
          sel == VMString[IF_TRUE_FALSE_] ||
          sel == VMString[IF_FALSE_TRUE_])) {
       // these bets are really safe - make uncommon even when recompiling
       // due to uncommon trap (if the ifTrue itself caused the trap,
       // rscope->isUncommonAt will be false, so this is safe)
       allowUnlikely = true;
     }
     if (allowUnlikely) {
       if (rscope->isUncommonAt(_bci, false)) {
         // ok, no uncommon trap here
       } else if (rscope->hasSubScopes(_bci)) {
         // has real send for ifTrue et al. -- must be NIC-compiled
         // make uncommon unlikely if no non-true/false receiver present
         RScopeBList* subs = rscope->subScopes(_bci);
         for (fint i = subs->length() - 1; i >= 0; i--) {
           RScope* s = subs->nth(i);
           SExpr* rcvr = s->receiverExpr();
           if (rcvr->hasMap()) {
             Map* m = rcvr->map();
             if (m != Memory-> true_map() &&
                 m != Memory->false_map()) {
               allowUnlikely = false;
               break;
             }
           }
         }
         if (WizardMode && !allowUnlikely)
           warning("SIC: non-bool receiver for ifTrue: et al. detected");
       }
       if (allowUnlikely) {
         // make unknown case unlikely despite 
         info->rcvr = info->rcvr->makeUnknownUnlikely(this);
       }
     }
     SExpr* rcvr = info->rcvr;
     SExpr* t = new ConstantSExpr(Memory->trueObj , r, NULL);
     SExpr* f = new ConstantSExpr(Memory->falseObj, r, NULL);
     // make sure we don't destroy splitting info; only add types if not
     // already present
     if (rcvr->findMap(Memory-> true_mapOop()) == NULL)
       rcvr = rcvr->mergeWith(t, NULL);
     if (rcvr->findMap(Memory->false_mapOop()) == NULL)
       rcvr = rcvr->mergeWith(f, NULL);
     return rcvr;
   }
   
   if (// binary integer arithmetic messages
       sel == VMString[PLUS] ||
       sel == VMString[MINUS] ||
       sel == VMString[PERCENT] ||
       sel == VMString[LESS_THAN] ||
       sel == VMString[LESS_EQUAL] || 
       sel == VMString[GREATER_EQUAL] ||
       sel == VMString[GREATER_THAN] |
       // integer looping messages
       sel == VMString[TO_DO_] ||
       sel == VMString[UP_TO_DO_] ||
       sel == VMString[DOWN_TO_DO_] ||
       sel == VMString[TO_BY_DO_] ||
       sel == VMString[UP_TO_BY_DO_] ||
       sel == VMString[DOWN_TO_BY_DO_] ||
       // unary integer arithmetic selectors
       sel == VMString[SUCCESSOR] ||
       sel == VMString[SUCC] ||
       sel == VMString[PREDECESSOR] ||
       sel == VMString[PRED]) {
     if (info->rcvr->findMap(Memory->smi_map->enclosing_mapOop())) return info->rcvr;
     if (PrintInlining) {
       lprintf("%*s*type-predicting %s\n", (void*)depth, "",
               sel->copy_null_terminated());
     }
     info->predicted = true;
     SExpr* res =
       info->rcvr->mergeWith(new MapSExpr(Memory->smi_map->enclosing_mapOop(),
                                          r, NULL), NULL);
     if (theSIC->useUncommonTraps && rscope->isUncommonAt(_bci, false)) {
       info->rcvr = res = res->makeUnknownUnlikely(this);
     }
     return res;
   }
   
   return info->rcvr;
 }