Example #1
0
Expr* PrimInliner::generate_cond(BranchOpCode cond, NodeBuilder* gen, PReg* resPReg) {
// generate code loading true or false depending on current condition code
// Note: condition is negated in order to provoke a certain code order
//       when compiling whileTrue loops - gri 6/26/96

  // n2: conditional branch
  BranchNode* n2 = NodeFactory::new_BranchNode(not(cond));
  gen->append(n2);

  // tAsgn: true branch
  ConstPReg* tPReg = new_ConstPReg(gen->scope(), trueObj);
  AssignNode* tAsgn = NodeFactory::new_AssignNode(tPReg, resPReg);
  ConstantExpr* tExpr = new ConstantExpr(trueObj, resPReg, tAsgn);
  n2->append(0, tAsgn);

  // fAsgn: false branch
  ConstPReg* fPReg = new_ConstPReg(gen->scope(), falseObj);
  AssignNode* fAsgn = NodeFactory::new_AssignNode(fPReg, resPReg);
  ConstantExpr* fExpr = new ConstantExpr(falseObj, resPReg, fAsgn);
  n2->append(1, fAsgn);

  // ftm: false & true branch merger
  MergeNode* ftm = NodeFactory::new_MergeNode(fAsgn, tAsgn);
  Expr* result = new MergeExpr(fExpr, tExpr, resPReg, ftm);
  gen->setCurrent(ftm);
  return result;
}
Example #2
0
  SExpr* SPrimScope::tryTypeCheck() {
    // for inlined prims, try to see if primitive will always fail
    if (!InlinePrimitives) return NULL;
    
    bool fail = false;
    switch (pd->type()) {
     case NotReallyAPrimitive:
     case InternalPrimitive:
      fatal("cannot call an internal primitive from Self code");
      return NULL;
     case IntComparisonPrimitive:
     case IntArithmeticPrimitive:
      // must have two smis
      fail = CHECK_INT(receiver) || CHECK_INT(args->last());
      break;

     case FloatArithmeticPrimitive:
     case FloatComparisonPrimitive:
      // must have two floats
      fail = CHECK_FLOAT(receiver) || CHECK_FLOAT(args->last());
      break;
      
     case AtPrimitive:
     case AtPutPrimitive:
      // must have array rcvr and smi arg
      fail = TYPECHECK(receiver, is_objVector()) || CHECK_INT(args->last());
      break;
     case SizePrimitive:
      // must have array rcvr
      fail = TYPECHECK(receiver, is_objVector());
      break;

     case ByteAtPutPrimitive:
      // stored value must be 0..255; for now, test only for integer
      fail = CHECK_INT(args->nth(0));
      // fall through
     case ByteAtPrimitive:
      // must have array rcvr and smi arg
      fail |= TYPECHECK(receiver, is_byteVector()) || CHECK_INT(args->last());
      break;
     case ByteSizePrimitive:
      // must have array rcvr
      fail = TYPECHECK(receiver, is_byteVector());
      break;

     default:
      return NULL;          
    }
    
    if (fail) {
      // primitive will always fail
      ConstPReg* error = new_ConstPReg(_sender, VMString[BADTYPEERROR]);
      Node* dummy;
      MergeNode* mdummy = NULL;
      return genPrimFailure(NULL, error, dummy, mdummy, resultPR, false);
    } else {
      return NULL;
    }
  }
Example #3
0
SExpr* SPrimScope::tryConstantFold() {
    const fint MaxPrimArgs = 5; // fix switch stmt below when increasing this
    if (!pd->canBeConstantFolded() || nargs > MaxPrimArgs) return NULL;
    oop a[MaxPrimArgs];         // argument oops
    if (!receiver->isConstantSExpr()) return NULL;
    oop r = receiver->constant();
    // get arguments (NB: args is in reverse order)
    fint i;
    for (i = 0; i < nargs; i++) {
      if (!args->nth(i)->isConstantSExpr()) return NULL;
      a[nargs - i - 1] = args->nth(i)->constant();
    };
    // ok, all args are consts: call the primitive
    oop res;
    fntype f = pd->fn();
    switch(nargs) {
     case 0:    res = f(r); break;
     case 1:    res = f(r, a[0]); break;
     case 2:    res = f(r, a[0], a[1]); break;
     case 3:    res = f(r, a[0], a[1], a[2]); break;
     case 4:    res = f(r, a[0], a[1], a[2], a[3]); break;
     case 5:    res = f(r, a[0], a[1], a[2], a[3], a[4]); break;
     default:   ShouldNotReachHere();
    }

    if (PrintInlining) {
      char buf[1024];
      char* b = buf;
      mysprintf(b, "%*s*constant-folding %s %s ", (void*)depth, "",
                r->debug_print(), pd->name());
      for (i = 0; i < nargs; i++) {
        mysprintf(b, "%s ", a[i]->debug_print());
      }
      mysprintf(b, "--> %s\n", res->debug_print());
      lprintf(buf);
    }

    // should scan backwards here and discard all nodes computing the args

    if (res->is_mark()) {
      // primitive will always fail
      ConstPReg* error = new_ConstPReg(_sender, res->memify());
      Node* dummy;
      MergeNode* mdummy = NULL;
      SExpr* failExpr =
        genPrimFailure(NULL, error, dummy, mdummy, resultPR, false);
      return failExpr;
    } else {
      theNodeGen->loadOop(res, resultPR);
      return new ConstantSExpr(res, resultPR, theNodeGen->current);
    }
  }
Example #4
0
Expr* PrimInliner::smi_Mod(Expr* x, Expr* y) {
  if (y->preg()->isConstPReg()) {
    assert(y->is_smi(), "type check should have failed");
    int d = smiOop(((ConstPReg*)y->preg())->constant)->value();
    if (is_power_of_2(d)) {
      // replace it with mask
      ConstPReg* preg = new_ConstPReg(_scope, as_smiOop(d-1));
      return smi_BitOp(tAndArithOp, x, new ConstantExpr(preg->constant, preg, _gen->_current));
    }
  }
  // otherwise leave it alone
  return NULL;
}
Example #5
0
Expr* PrimInliner::tryConstantFold() {
  // Returns the result if the primitive call has been constant folded
  // successfully; returns NULL otherwise.
  // Note: The result may be a marked oop - which has to be unmarked
  // before using it - and which indicates that the primitive will fail
  // always.
  if (!_pdesc->can_be_constant_folded()) {
    // check for Symbol>>at: before declaring failure
    if ((equal(_pdesc->name(), "primitiveIndexedByteAt:ifFail:") ||
         equal(_pdesc->name(), "primitiveIndexedByteCharacterAt:ifFail:")) &&
        parameter(0)->hasKlass() && parameter(0)->klass() == Universe::symbolKlassObj()) {
      // the at: primitive can be constant-folded for symbols
      // what if the receiver is a constant string? unfortunately, Smalltalk has
      // "assignable constants" like Fortran...
    } else {
      return NULL;
    }
  }
  // get parameters
  int i = number_of_parameters();
  oop* args = NEW_RESOURCE_ARRAY(oop, i);
  while (i > 0) {
    i--;
    Expr* arg = parameter(i);
    if (!arg->isConstantExpr()) return NULL;
    args[i] = arg->constant();
  }
  // all parameters are constants, so call primitive
  oop res = _pdesc->eval(args);
  if (res->is_mark()) {
    // primitive failed
    return primitiveFailure(unmarkSymbol(res));
  } else if (res->is_mem() && !res->is_old()) {
    // must tenure result because nmethods aren't scavenged
    if (res->is_double()) {
      res = oopFactory::clone_double_to_oldspace(doubleOop(res));
    } else {
      // don't know how to tenure non-doubles
      warning("const folding: primitive %s is returning non-tenured object", _pdesc->name());
      return NULL;
    }
  }
  ConstPReg* constResult = new_ConstPReg(_scope, res);
  SAPReg* result = new SAPReg(_scope);
  _gen->append(NodeFactory::new_AssignNode(constResult, result));
  if (CompilerDebug) cout(PrintInlining)->print("%*sconstant-folding %s --> %#x\n", _scope->depth + 2, "", _pdesc->name(), res);
  assert(!constResult->constant->is_mark(), "result must not be marked");
  return new ConstantExpr(res, constResult, _gen->current());
}
Example #6
0
Expr* PrimInliner::smi_Comparison(BranchOpCode cond, 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

  // n1: comparison & treatment of tag error
  Node* n1;
  ConstPReg* n1PReg;
  AssignNode* n1Err;
  ConstantExpr* n1Expr;
  if (intBoth) {
    // tag error cannot occur
    n1 = NodeFactory::new_ArithRRNode(new NoPReg(_scope), arg1->preg(), tCmpArithOp, arg2->preg());
  } else {
    // tag error can occur
    n1 = NodeFactory::new_TArithRRNode(new NoPReg(_scope), arg1->preg(), tCmpArithOp, arg2->preg(), intArg1, intArg2);
    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);
  }
  _gen->append(n1);

  Expr* result = generate_cond(cond, _gen, resPReg);

  // continuation
  if (!intBoth) {
    // failure can occur
    if (shouldUseUncommonTrap()) {
      // simply do an uncommon trap
      n1Err->append(NodeFactory::new_UncommonNode(_gen->copyCurrentExprStack(), _bci /*_failure_block->begin_bci()*/));
    } else {
      // treat failure case
      result = merge_failure_block(result->node(), result, n1Err, n1Expr, false);
    }
  }
  return result;
}
Example #7
0
Expr* PrimInliner::obj_class(bool has_receiver) {
  assert_no_failure_block();
  if (has_receiver) assert_receiver();

  Expr*   obj     = parameter(0);
  if (obj->hasKlass()) {
    // constant-fold it
    klassOop k = obj->klass();
    return new ConstantExpr(k, new_ConstPReg(_scope, k), NULL);
  } else {
    SAPReg* resPReg = new SAPReg(_scope);
    InlinedPrimitiveNode* n = NodeFactory::new_InlinedPrimitiveNode(
      InlinedPrimitiveNode::obj_klass, resPReg, NULL, obj->preg()
    );
    _gen->append(n);
    // don't know exactly what it is - just use PIC info
    return new UnknownExpr(resPReg, n);
  }
}
Example #8
0
Expr* PrimInliner::primitiveFailure(symbolOop failureCode) {
  // compile a failing primitive
  if (CompilerDebug) cout(PrintInlining)->print("%*sprimitive %s will fail: %s\n", _scope->depth + 2, "", _pdesc->name(), failureCode->as_string());
  if (_failure_block == NULL) {
    error("\nPotential compiler bug: compiler believes primitive %s will fail\nwith error %s, but primitive has no failure block.\n",
          _pdesc->name(), failureCode->as_string());
    return NULL;
  }
  // The byte code compiler stores the primitive result in a temporary (= the parameter of
  // the inlined failure block).  Thus, we store res in the corresponding temp Expr so that
  // its value isn't forgotten (the default Expr for temps is UnknownExpr) and restore the
  // temp's original value afterwards. This is safe because within the failure block that
  // temporary is treated as a parameter and therefore is read-only.
  AssignmentFinder closure(_failure_block);
  assert(closure.interval != NULL, "no assignment found");
  Expr* old_temp = _scope->temporary(closure.tempNo);	// save temp
  Expr* res = new ConstantExpr(failureCode, new_ConstPReg(_scope, failureCode), _gen->current());
  _scope->set_temporary(closure.tempNo, res);
  closure.set_prim_failure(false);		// allow inlining sends in failure branch
  _gen->generate_subinterval(closure.interval, true);
  _scope->set_temporary(closure.tempNo, old_temp);
  return _gen->exprStack()->pop();		// restore temp
}
Example #9
0
void InlinedScope::createTemporaries(int nofTemps) {
  // add nofTemps temporaries (may be called multiple times)
  int firstNew;
  if (!hasTemporaries()) {
    // first time we're called
    _temporaries = new GrowableArray<Expr*>(nofTemps, nofTemps, NULL);
    // The canonical model has the context in the first temporary.
    // To preserve this model the first temporary is aliased to _context.
    // Lars, 3/8/96
    if (_context) {
      _temporaries->at_put(0, new ContextExpr(_context));
      firstNew = 1;
    } else {
      firstNew = 0;
    }
 } else {
    // grow existing temp array
    const GrowableArray<Expr*>* oldTemps = _temporaries;
    const int n = nofTemps + oldTemps->length();
    _temporaries = new GrowableArray<Expr*>(n, n, NULL);
    firstNew = oldTemps->length();
    nofTemps += oldTemps->length();
    for (int i = 0; i < firstNew; i++) _temporaries->at_put(i, oldTemps->at(i));
  }
  // initialize new temps
 ConstPReg* nil = new_ConstPReg(this, nilObj);
  for (int i = firstNew; i < nofTemps; i++) {
    PReg* r = new PReg(this);
    _temporaries->at_put(i, new UnknownExpr(r, NULL));
    if (isTop()) {
      // temps are initialized by PrologueNode
    } else {
      gen()->append(NodeFactory::new_AssignNode(nil, r));
    }
  }
}
Example #10
0
  SExpr* SPrimScope::genPrimFailure(PrimNode* call, PReg* errorReg,
                                    Node*& test, MergeNode*& merge,
                                    PReg* resultReg, bool failure) {
    // generate primitive failure code
    // two modes:
    //    if call == NULL, omit the test for failure because it's already
    //          been generated (inlined prim.); in this case, errorReg
    //          must be set
    //    if call != NULL, generate test code (setting test & merge node args)
    // returns the result of the failure branch

    // pop prim args (they're not on the expr stack anymore in the fail branch)
    while (npop-- > 0) exprStack()->pop();
    
    SCodeScope* s = sender();
    NodeGen* ng = theNodeGen;
    if (call) {
      fint b = bci();
      SAPReg* t = new SAPReg(s, b, b);
      // extract tag field and test for mark tag
      ng->append(new ArithRCNode(AndArithOp, call->dest(), Tag_Mask, t));
      ng->append(new ArithRCNode(SubCCArithOp, t, Tag_Mask, ng->noPR));
      test = ng->append(new BranchNode(NEBranchOp));
      // failure branch; load error string
      if (!errorReg) errorReg = new SAPReg(s, b, b);
      ng->current = 
        test->append(new ArithRCNode(SubArithOp, call->dest(),
                                     Mark_Tag-Mem_Tag, errorReg));
    }

    SExpr* failReceiver = hasFailBlock ? failBlock : receiver;
    SendInfo* info = new SendInfo(failReceiver, NormalLookupType, false, false,
                                  (stringOop)failSelector, NULL);
    info->computeNSends(rscope, bci());
    info->primFailure = failure;
    info->restartPrim = call == NULL;   // restart inlined prims (unc. traps)
    s->exprStack->push(failReceiver);
    if (errorReg->isConstPReg()) {
      s->exprStack->push(new ConstantSExpr(((ConstPReg*)errorReg)->constant,
                                           errorReg, ng->current));
    } else {
      s->exprStack->push(new MapSExpr(Memory->stringObj->map()->enclosing_mapOop(),
                                      errorReg, ng->current));
    }
    ConstPReg* failSelReg = new_ConstPReg(s, selector());
    s->exprStack->push(new ConstantSExpr(selector(), failSelReg, NULL));
    SExpr* res = s->inlineSend(info);

    if (res->isNoResultSExpr()) {
      // never returns
      ng->current = merge; // set to NULL if no merge
    } 
    else {
      if (needZap) {
        assert(failBlock->preg()->isBlockPReg(), "should be a block");
        ng->zapBlock((BlockPReg*)failBlock->preg());
      }
      ng->move(res->preg(), resultReg);
      res = res->shallowCopy(resultReg, ng->current);
      // moved creation down from before if res->isNoResult... 
      //   to avoid creating unreachable merge -- dmu
      if (merge == NULL) merge = new MergeNode("genPrimFailure merge"); 
      ng->append(merge);
    }
    return res;
  }
Example #11
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;
  }
Example #12
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);
    }
  }
Example #13
0
 ConstPReg* SPrimScope::falsePR() {
   return new_ConstPReg(_sender, Memory->falseObj);
 }
Example #14
0
 ConstPReg* SPrimScope::truePR() {
   return new_ConstPReg(_sender, Memory->trueObj);
 }
Example #15
0
 void NodeGen::loadOop(oop p, PReg* dest) {
   APPEND(new AssignNode(new_ConstPReg(currentScope(), p), dest));
 }
Example #16
0
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;
}