primInliner.cpp

Go to the documentation of this file.
00001 /* Copyright 1994 - 1996 LongView Technologies L.L.C. $Revision: 1.100 $ */
00002 /* Copyright (c) 2006, Sun Microsystems, Inc.
00003 All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 
00006 following conditions are met:
00007 
00008     * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
00009     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 
00010           disclaimer in the documentation and/or other materials provided with the distribution.
00011     * Neither the name of Sun Microsystems nor the names of its contributors may be used to endorse or promote products derived 
00012           from this software without specific prior written permission.
00013 
00014 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT 
00015 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
00016 THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
00017 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
00018 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
00019 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
00020 
00021 
00022 */
00023 
00024 # include "incls/_precompiled.incl"
00025 
00026 # ifdef DELTA_COMPILER
00027 # include "incls/_primInliner.cpp.incl"
00028 
00029 inline bool equal(char* s, char* t) { return strcmp(s, t) == 0; }
00030 
00031 
00032 void PrimInliner::assert_failure_block() {
00033   assert(_failure_block != NULL, "primitive must have a failure block");
00034 }
00035 
00036 
00037 void PrimInliner::assert_no_failure_block() {
00038   assert(_failure_block == NULL, "primitive doesn't have a failure block");
00039 }
00040 
00041 
00042 void PrimInliner::assert_receiver() {
00043   assert(parameter(0) == _scope->self(), "first parameter must be self");
00044 }
00045 
00046 
00047 int PrimInliner::log2(int x) const {
00048   int i = -1;
00049   int p =  1;
00050   while (p != 0 && p <= x) {
00051     // p = 2^(i+1) && p <= x (i.e., 2^(i+1) <= x)
00052     i++; p *= 2;
00053   }
00054   // p = 2^(i+1) && x < p (i.e., 2^i <= x < 2^(i+1))
00055   // (if p = 0 then overflow occured and i = 31)
00056   return i;
00057 }
00058 
00059 
00060 Expr* PrimInliner::tryConstantFold() {
00061   // Returns the result if the primitive call has been constant folded
00062   // successfully; returns NULL otherwise.
00063   // Note: The result may be a marked oop - which has to be unmarked
00064   // before using it - and which indicates that the primitive will fail
00065   // always.
00066   if (!_pdesc->can_be_constant_folded()) {
00067     // check for Symbol>>at: before declaring failure
00068     if ((equal(_pdesc->name(), "primitiveIndexedByteAt:ifFail:") ||
00069          equal(_pdesc->name(), "primitiveIndexedByteCharacterAt:ifFail:")) &&
00070         parameter(0)->hasKlass() && parameter(0)->klass() == Universe::symbolKlassObj()) {
00071       // the at: primitive can be constant-folded for symbols
00072       // what if the receiver is a constant string? unfortunately, Smalltalk has
00073       // "assignable constants" like Fortran...
00074     } else {
00075       return NULL;
00076     }
00077   }
00078   // get parameters
00079   int i = number_of_parameters();
00080   oop* args = NEW_RESOURCE_ARRAY(oop, i);
00081   while (i > 0) {
00082     i--;
00083     Expr* arg = parameter(i);
00084     if (!arg->isConstantExpr()) return NULL;
00085     args[i] = arg->constant();
00086   }
00087   // all parameters are constants, so call primitive
00088   oop res = _pdesc->eval(args);
00089   if (res->is_mark()) {
00090     // primitive failed
00091     return primitiveFailure(unmarkSymbol(res));
00092   } else if (res->is_mem() && !res->is_old()) {
00093     // must tenure result because nmethods aren't scavenged
00094     if (res->is_double()) {
00095       res = oopFactory::clone_double_to_oldspace(doubleOop(res));
00096     } else {
00097       // don't know how to tenure non-doubles
00098       warning("const folding: primitive %s is returning non-tenured object", _pdesc->name());
00099       return NULL;
00100     }
00101   }
00102   ConstPReg* constResult = new_ConstPReg(_scope, res);
00103   SAPReg* result = new SAPReg(_scope);
00104   _gen->append(NodeFactory::new_AssignNode(constResult, result));
00105   if (CompilerDebug) cout(PrintInlining)->print("%*sconstant-folding %s --> %#x\n", _scope->depth + 2, "", _pdesc->name(), res);
00106   assert(!constResult->constant->is_mark(), "result must not be marked");
00107   return new ConstantExpr(res, constResult, _gen->current());
00108 }
00109 
00110 
00111 Expr* PrimInliner::tryTypeCheck() {
00112   // Check if we have enough type information to prove that the primitive is going to fail;
00113   // if so, directly compile failure block (important for mixed-mode arithmetic).
00114   // Returns the failure result if the primitive call has been proven
00115   // to fail; returns NULL otherwise.
00116   // Should extend code to do general type compatibility test (including MergeExprs, e.g. for 
00117   // booleans) -- fix this later.  -Urs 11/95
00118   int num = number_of_parameters();
00119   for (int i = 0; i < num; i++) {
00120     Expr* a = parameter(i);
00121     if (a->hasKlass()) {
00122       Expr* primArgType = _pdesc->parameter_klass(i, a->preg(), NULL);
00123       if (primArgType && primArgType->hasKlass() && (a->klass() != primArgType->klass())) {
00124         // types differ -> primitive must fail
00125         return primitiveFailure(failureSymbolForArg(i));
00126       }
00127     }
00128   }
00129   return NULL;
00130 }
00131 
00132 
00133 symbolOop PrimInliner::failureSymbolForArg(int i) {
00134   assert(i >= 0 && i < number_of_parameters(), "bad index");
00135   switch (i) {
00136     case  0: return vmSymbols::receiver_has_wrong_type();
00137     case  1: return vmSymbols::first_argument_has_wrong_type();
00138     case  2: return vmSymbols::second_argument_has_wrong_type();
00139     case  3: return vmSymbols::third_argument_has_wrong_type();
00140     case  4: return vmSymbols::fourth_argument_has_wrong_type();
00141     case  5: return vmSymbols::fifth_argument_has_wrong_type();
00142     case  6: return vmSymbols::sixth_argument_has_wrong_type();
00143     case  7: return vmSymbols::seventh_argument_has_wrong_type();
00144     case  8: return vmSymbols::eighth_argument_has_wrong_type();
00145     case  9: return vmSymbols::ninth_argument_has_wrong_type();
00146     case 10: return vmSymbols::tenth_argument_has_wrong_type();
00147     default: return vmSymbols::argument_has_wrong_type();
00148   }
00149 }
00150 
00151 
00152 // Helper class to find the first assignment to a temporary in a failure
00153 // block and the remaining method interval (without the assignment).
00154 class AssignmentFinder: public SpecializedMethodClosure {
00155  public:
00156   int             tempNo;       // the temporary to which the assignment took place
00157   MethodInterval* block;        // the block over which to iterate
00158   MethodInterval* interval;     // the rest of the block without the assignment
00159 
00160   AssignmentFinder(MethodInterval* b) : SpecializedMethodClosure() {
00161     block = b;
00162     interval = NULL;
00163     MethodIterator iter(block, this);
00164   }
00165   void instruction()            { abort(); }
00166   void store_temporary(int no)  { 
00167     tempNo = no; 
00168     interval = MethodIterator::factory->new_MethodInterval(method(), NULL, next_bci(), block->end_bci()); 
00169   }
00170 };
00171 
00172 
00173 Expr* PrimInliner::primitiveFailure(symbolOop failureCode) {
00174   // compile a failing primitive
00175   if (CompilerDebug) cout(PrintInlining)->print("%*sprimitive %s will fail: %s\n", _scope->depth + 2, "", _pdesc->name(), failureCode->as_string());
00176   if (_failure_block == NULL) {
00177     error("\nPotential compiler bug: compiler believes primitive %s will fail\nwith error %s, but primitive has no failure block.\n",
00178           _pdesc->name(), failureCode->as_string());
00179     return NULL;
00180   }
00181   // The byte code compiler stores the primitive result in a temporary (= the parameter of
00182   // the inlined failure block).  Thus, we store res in the corresponding temp Expr so that
00183   // its value isn't forgotten (the default Expr for temps is UnknownExpr) and restore the
00184   // temp's original value afterwards. This is safe because within the failure block that
00185   // temporary is treated as a parameter and therefore is read-only.
00186   AssignmentFinder closure(_failure_block);
00187   assert(closure.interval != NULL, "no assignment found");
00188   Expr* old_temp = _scope->temporary(closure.tempNo);   // save temp
00189   Expr* res = new ConstantExpr(failureCode, new_ConstPReg(_scope, failureCode), _gen->current());
00190   _scope->set_temporary(closure.tempNo, res);
00191   closure.set_prim_failure(false);              // allow inlining sends in failure branch
00192   _gen->generate_subinterval(closure.interval, true);
00193   _scope->set_temporary(closure.tempNo, old_temp);
00194   return _gen->exprStack()->pop();              // restore temp
00195 }
00196 
00197 Expr* PrimInliner::merge_failure_block(Node* ok_exit, Expr* ok_result, Node* failure_exit, Expr* failure_code, bool ok_result_is_read_only) {
00198   assert(failure_code->hasKlass() && failure_code->klass() == Universe::symbolKlassObj(), "failure code must be a symbol");
00199   _cannotFail = false;
00200   // push failure code
00201   _gen->setCurrent(failure_exit);
00202   _gen->exprStack()->push(failure_code, _scope, failure_exit->bci());
00203   // code for failure block
00204   _gen->generate_subinterval(_failure_block, true);
00205   Expr* failure_block_result = _gen->exprStack()->pop();
00206   if (failure_block_result->isNoResultExpr()) {
00207     // failure doesn't reach here (e.g., uncommon branch)
00208     assert(!_gen->current() || _gen->current() == NodeBuilder::EndOfCode, "shouldn't reach here");
00209     _gen->setCurrent(ok_exit);
00210     return ok_result;
00211   } else {
00212     if (ok_result_is_read_only) {
00213       // cannot assign to ok_result directly => introduce extra PReg & extra assignment
00214       // (was bug detected with new backend: assignment to ok_result is not legal if it
00215       // refers to parameter/receiver of the method calling the primitive - gri 6/29/96)
00216       PReg* resPReg = new SAPReg(_scope);
00217       Node* node    = NodeFactory::new_AssignNode(ok_result->preg(), resPReg);
00218       Expr* resExpr = ok_result->shallowCopy(resPReg, node);
00219       ok_exit->append(node);
00220       ok_exit = node;
00221       ok_result = resExpr;
00222     }
00223     _gen->append(NodeFactory::new_AssignNode(failure_block_result->preg(), ok_result->preg()));
00224     // merge after failure block
00225     MergeNode* prim_exit = NodeFactory::new_MergeNode(_failure_block->end_bci());
00226     _gen->append(prim_exit);
00227     ok_exit->append(prim_exit);
00228     _gen->setCurrent(prim_exit);
00229     return new MergeExpr(ok_result, failure_block_result, ok_result->preg(), prim_exit);
00230   }
00231 }
00232 
00233 class PrimSendFinder : public SpecializedMethodClosure {
00234 public:
00235   RScope* rs;
00236   bool was_executed;
00237 
00238   PrimSendFinder(RScope* rs)                    { this->rs = rs; was_executed = false; rs->extend(); }
00239   virtual void normal_send(InterpretedIC* ic)   { check_send(ic); }
00240   virtual void self_send  (InterpretedIC* ic)   { check_send(ic); }
00241   virtual void super_send (InterpretedIC* ic)   { check_send(ic); }
00242   void check_send(InterpretedIC* ic) {
00243     GrowableArray<RScope*>* sub = rs->subScopes(bci());
00244     if (sub->length() == 1 && sub->first()->isUntakenScope()) {
00245       // this send was never taken
00246     } else {
00247       was_executed = true;                      // this send was taken in recompilee
00248     }
00249   }
00250 };
00251 
00252 
00253 inline bool PrimInliner::basic_shouldUseUncommonTrap() const {
00254   ResourceMark rm;
00255   if (!theCompiler->useUncommonTraps) return false; 
00256   // first check if recompilee has a taken uncommon branch 
00257   // NOTE: the uncommon branch should be at _failure_block->begin_bci(), not _bci, but
00258   // deoptimization currently breaks if that's so -- please fix this, Lars
00259   // (search for new_UncommonNode below when fixing it)
00260   if (_scope->rscope->isNotUncommonAt(_bci)) return false;
00261   //if (_scope->rscope->isNotUncommonAt(_failure_block->begin_bci())) return false;
00262   if (_scope->rscope->isUncommonAt(_bci)) return true;
00263   //if (_scope->rscope->isUncommonAt(_failure_block->begin_bci())) return true;
00264   // now check if recompilee had code for the failure block, and any send in it was taken
00265   if (!_scope->rscope->get_nmethod()) {
00266     return true;      // if it's not compiled, assume that using uncommon branch is ok
00267   }
00268 #ifdef broken
00269   // This code doesn't really do the right thing; what's needed is something that
00270   // can determine whether the failure was taken in the previous version of compiled code.
00271   // If there's a send that's easy (ic dirty flag), but if everything in the failure block
00272   // was inlined...?  Could put a "removable trap" there to determine this.  fix this later
00273   // -Urs 8/96
00274   PrimSendFinder p(_scope->rscope);
00275   MethodIterator it(_failure_block, &p);
00276   return !p.was_executed;
00277 #endif
00278   // for now, try the aggressive approach: no proof that it was taken, so guess that it's uncommon
00279   return true;
00280 }
00281 
00282 bool PrimInliner::shouldUseUncommonTrap() {
00283   // remember result of call in _usingUncommonTrap
00284   _usingUncommonTrap = basic_shouldUseUncommonTrap(); 
00285   return _usingUncommonTrap;
00286 }
00287 
00288 Expr* PrimInliner::smi_ArithmeticOp(ArithOpCode op, Expr* arg1, Expr* arg2) {
00289   assert_failure_block();
00290   assert_receiver();
00291   
00292   // parameters & result registers
00293   bool       intArg1      = arg1->is_smi();
00294   bool       intArg2      = arg2->is_smi();
00295   bool       intBoth      = intArg1 && intArg2;                 // if true, tag error cannot occur
00296   SAPReg*    resPReg      = new SAPReg(_scope);                 // holds the result if primitive didn't fail
00297   SAPReg*    errPReg      = new SAPReg(_scope);                 // holds the error message if primitive failed
00298   MergeNode* failureStart = NodeFactory::new_MergeNode(_failure_block->begin_bci());
00299 
00300   // n1: operation & treatment of tag error
00301   Node* n1;
00302   AssignNode*  n1Err;
00303   ConstantExpr* n1Expr = NULL;
00304   if (intBoth) {
00305     // tag error cannot occur
00306     n1 = NodeFactory::new_ArithRRNode(resPReg, arg1->preg(), op, arg2->preg());
00307   } else {
00308     // tag error can occur
00309     n1 = NodeFactory::new_TArithRRNode(resPReg, arg1->preg(), op, arg2->preg(), intArg1, intArg2);
00310     if (shouldUseUncommonTrap()) {
00311       // simply jump to uncommon branch code
00312       n1->append(1, failureStart);
00313     } else {
00314       ConstPReg* n1PReg = new_ConstPReg(_scope, vmSymbols::first_argument_has_wrong_type());
00315       n1Err = NodeFactory::new_AssignNode(n1PReg, errPReg);
00316       n1Expr = new ConstantExpr(n1PReg->constant, errPReg, n1Err);
00317       n1->append(1, n1Err);
00318       n1Err->append(failureStart);
00319     }
00320   }
00321   _gen->append(n1);
00322   Expr* result = new KlassExpr(smiKlassObj, resPReg, n1);
00323 
00324   // n2: overflow check & treatment of overflow
00325   const bool taken_is_uncommon = true;
00326   BranchNode* n2 = NodeFactory::new_BranchNode(VSBranchOp, taken_is_uncommon);
00327   AssignNode* n2Err;
00328   ConstantExpr* n2Expr = NULL;
00329   if (shouldUseUncommonTrap()) {
00330     // simply jump to uncommon branch code
00331     n2->append(1, failureStart);
00332   } else {
00333     ConstPReg* n2PReg = new_ConstPReg(_scope, vmSymbols::smi_overflow());
00334     n2Err = NodeFactory::new_AssignNode(n2PReg, errPReg);
00335     n2Expr = new ConstantExpr(n2PReg->constant, errPReg, n2Err);
00336     n2->append(1, n2Err);
00337     n2Err->append(failureStart);
00338   }
00339   _gen->append(n2);
00340 
00341   // continuation
00342   if (shouldUseUncommonTrap()) {
00343     // uncommon branch instead of failure code
00344     failureStart->append(NodeFactory::new_UncommonNode(_gen->copyCurrentExprStack(), _bci /*_failure_block->begin_bci()*/));
00345   } else {
00346     assert(n2Expr != NULL, "no error message defined");
00347     Expr* error;
00348     if (n1Expr != NULL) {
00349       error = new MergeExpr(n1Expr, n2Expr, errPReg, failureStart);
00350     } else {
00351       error = n2Expr;
00352     }
00353     result = merge_failure_block(n2, result, failureStart, error, false);
00354   }
00355   return result;
00356 }
00357 
00358 
00359 Expr* PrimInliner::smi_BitOp(ArithOpCode op, Expr* arg1, Expr* arg2) {
00360   assert_failure_block();
00361   assert_receiver();
00362 
00363   // parameters & result registers
00364   bool    intArg1 = arg1->is_smi();
00365   bool    intArg2 = arg2->is_smi();
00366   bool    intBoth = intArg1 && intArg2; // if true, tag error cannot occur
00367   SAPReg* resPReg = new SAPReg(_scope); // holds the result if primitive didn't fail
00368   SAPReg* errPReg = new SAPReg(_scope); // holds the error message if primitive failed
00369 
00370   // n1: operation & treatment of tag error
00371   Node*  n1;
00372   AssignNode* n1Err;
00373   ConstantExpr* n1Expr;
00374   if (intBoth) {
00375     // tag error cannot occur
00376     n1 = NodeFactory::new_ArithRRNode(resPReg, arg1->preg(), op, arg2->preg());
00377   } else {
00378     // tag error can occur
00379     n1 = NodeFactory::new_TArithRRNode(resPReg, arg1->preg(), op, arg2->preg(), intArg1, intArg2);
00380     ConstPReg* n1PReg = new_ConstPReg(_scope, vmSymbols::first_argument_has_wrong_type());
00381     n1Err = NodeFactory::new_AssignNode(n1PReg, errPReg);
00382     n1Expr = new ConstantExpr(n1PReg->constant, errPReg, n1Err);
00383     n1->append(1, n1Err);
00384   }
00385   _gen->append(n1);
00386 
00387   // continuation
00388   Expr* result = new KlassExpr(smiKlassObj, resPReg, n1);
00389   if (!intBoth) {
00390     // failure can occur
00391     if (shouldUseUncommonTrap()) {
00392       // simply do an uncommon trap
00393       n1Err->append(NodeFactory::new_UncommonNode(_gen->copyCurrentExprStack(), _bci /*_failure_block->begin_bci()*/));
00394     } else {
00395       // treat failure case
00396       result = merge_failure_block(n1, result, n1Err, n1Expr, false);
00397     }
00398   }
00399   return result;
00400 }
00401 
00402 
00403 Expr* PrimInliner::smi_Div(Expr* x, Expr* y) {
00404   if (y->preg()->isConstPReg()) {
00405     assert(y->is_smi(), "type check should have failed");
00406     int d = smiOop(((ConstPReg*)y->preg())->constant)->value();
00407     if (is_power_of_2(d)) {
00408       // replace it with shift
00409       ConstPReg* preg = new_ConstPReg(_scope, as_smiOop(-log2(d)));
00410       return smi_BitOp(tShiftArithOp, x, new ConstantExpr(preg->constant, preg, _gen->_current));
00411     }
00412   }
00413   // otherwise leave it alone
00414   return NULL;
00415 }
00416 
00417 
00418 Expr* PrimInliner::smi_Mod(Expr* x, Expr* y) {
00419   if (y->preg()->isConstPReg()) {
00420     assert(y->is_smi(), "type check should have failed");
00421     int d = smiOop(((ConstPReg*)y->preg())->constant)->value();
00422     if (is_power_of_2(d)) {
00423       // replace it with mask
00424       ConstPReg* preg = new_ConstPReg(_scope, as_smiOop(d-1));
00425       return smi_BitOp(tAndArithOp, x, new ConstantExpr(preg->constant, preg, _gen->_current));
00426     }
00427   }
00428   // otherwise leave it alone
00429   return NULL;
00430 }
00431 
00432 
00433 Expr* PrimInliner::smi_Shift(Expr* arg1, Expr* arg2) {
00434   if (parameter(1)->preg()->isConstPReg()) {
00435     // inline if the shift count is a constant
00436     assert(arg2->is_smi(), "type check should have failed");
00437     return smi_BitOp(tShiftArithOp, arg1, arg2);
00438   }
00439   // otherwise leave it alone
00440   return NULL;
00441 }
00442 
00443 
00444 static BranchOpCode not(BranchOpCode cond) {
00445   switch (cond) {
00446     case EQBranchOp : return NEBranchOp;
00447     case NEBranchOp : return EQBranchOp;
00448     case LTBranchOp : return GEBranchOp;
00449     case LEBranchOp : return GTBranchOp;
00450     case GTBranchOp : return LEBranchOp;
00451     case GEBranchOp : return LTBranchOp;
00452     case LTUBranchOp: return GEUBranchOp;
00453     case LEUBranchOp: return GTUBranchOp;
00454     case GTUBranchOp: return LEUBranchOp;
00455     case GEUBranchOp: return LTUBranchOp;
00456     case VSBranchOp : return VCBranchOp;
00457     case VCBranchOp : return VSBranchOp;
00458   }
00459   ShouldNotReachHere();
00460   return EQBranchOp;
00461 }
00462 
00463 
00464 Expr* PrimInliner::generate_cond(BranchOpCode cond, NodeBuilder* gen, PReg* resPReg) {
00465 // generate code loading true or false depending on current condition code
00466 // Note: condition is negated in order to provoke a certain code order
00467 //       when compiling whileTrue loops - gri 6/26/96
00468 
00469   // n2: conditional branch
00470   BranchNode* n2 = NodeFactory::new_BranchNode(not(cond));
00471   gen->append(n2);
00472 
00473   // tAsgn: true branch
00474   ConstPReg* tPReg = new_ConstPReg(gen->scope(), trueObj);
00475   AssignNode* tAsgn = NodeFactory::new_AssignNode(tPReg, resPReg);
00476   ConstantExpr* tExpr = new ConstantExpr(trueObj, resPReg, tAsgn);
00477   n2->append(0, tAsgn);
00478 
00479   // fAsgn: false branch
00480   ConstPReg* fPReg = new_ConstPReg(gen->scope(), falseObj);
00481   AssignNode* fAsgn = NodeFactory::new_AssignNode(fPReg, resPReg);
00482   ConstantExpr* fExpr = new ConstantExpr(falseObj, resPReg, fAsgn);
00483   n2->append(1, fAsgn);
00484 
00485   // ftm: false & true branch merger
00486   MergeNode* ftm = NodeFactory::new_MergeNode(fAsgn, tAsgn);
00487   Expr* result = new MergeExpr(fExpr, tExpr, resPReg, ftm);
00488   gen->setCurrent(ftm);
00489   return result;
00490 }
00491 
00492 
00493 Expr* PrimInliner::smi_Comparison(BranchOpCode cond, Expr* arg1, Expr* arg2) {
00494   assert_failure_block();
00495   assert_receiver();
00496 
00497   // parameters & result registers
00498   bool    intArg1 = arg1->is_smi();
00499   bool    intArg2 = arg2->is_smi();
00500   bool    intBoth = intArg1 && intArg2; // if true, tag error cannot occur
00501   SAPReg* resPReg = new SAPReg(_scope); // holds the result if primitive didn't fail
00502   SAPReg* errPReg = new SAPReg(_scope); // holds the error message if primitive failed
00503 
00504   // n1: comparison & treatment of tag error
00505   Node* n1;
00506   ConstPReg* n1PReg;
00507   AssignNode* n1Err;
00508   ConstantExpr* n1Expr;
00509   if (intBoth) {
00510     // tag error cannot occur
00511     n1 = NodeFactory::new_ArithRRNode(new NoPReg(_scope), arg1->preg(), tCmpArithOp, arg2->preg());
00512   } else {
00513     // tag error can occur
00514     n1 = NodeFactory::new_TArithRRNode(new NoPReg(_scope), arg1->preg(), tCmpArithOp, arg2->preg(), intArg1, intArg2);
00515     n1PReg = new_ConstPReg(_scope, vmSymbols::first_argument_has_wrong_type());
00516     n1Err = NodeFactory::new_AssignNode(n1PReg, errPReg);
00517     n1Expr = new ConstantExpr(n1PReg->constant, errPReg, n1Err);
00518     n1->append(1, n1Err);
00519   }
00520   _gen->append(n1);
00521 
00522   Expr* result = generate_cond(cond, _gen, resPReg);
00523 
00524   // continuation
00525   if (!intBoth) {
00526     // failure can occur
00527     if (shouldUseUncommonTrap()) {
00528       // simply do an uncommon trap
00529       n1Err->append(NodeFactory::new_UncommonNode(_gen->copyCurrentExprStack(), _bci /*_failure_block->begin_bci()*/));
00530     } else {
00531       // treat failure case
00532       result = merge_failure_block(result->node(), result, n1Err, n1Expr, false);
00533     }
00534   }
00535   return result;
00536 }
00537 
00538 
00539 Expr* PrimInliner::array_size() {
00540   assert(_failure_block == NULL, "primitive must have no failure block");
00541   assert_receiver();
00542 
00543   // parameters & result registers
00544   Expr*  array = parameter(0);
00545   Klass* klass = array->klass()->klass_part();
00546   int    lenOffs = klass->non_indexable_size();
00547 
00548   // get size
00549   SAPReg* res = new SAPReg(_scope);
00550   _gen->append(NodeFactory::new_LoadOffsetNode(res, array->preg(), lenOffs, true));
00551   return new KlassExpr(smiKlassObj, res, _gen->_current);
00552 }
00553 
00554 
00555 Expr* PrimInliner::array_at_ifFail(ArrayAtNode::AccessType access_type) {
00556   assert_failure_block();
00557   assert_receiver();
00558 
00559   // parameters & result registers
00560   Expr*   array    = parameter(0);
00561   Expr*   index    = parameter(1);
00562   SAPReg* resPReg  = new SAPReg(_scope);        // holds the result if primitive didn't fail
00563   SAPReg* errPReg  = new SAPReg(_scope);        // holds the error message if primitive failed
00564   Klass*  klass    = array->klass()->klass_part();
00565   int     lenOffs  = klass->non_indexable_size();
00566   int     arrOffs  = lenOffs + 1;
00567   
00568   // at node
00569   ArrayAtNode* at = NodeFactory::new_ArrayAtNode(
00570     access_type, array->preg(), index->preg(), index->is_smi(), resPReg, errPReg, arrOffs, lenOffs
00571   );
00572   _gen->append(at);
00573 
00574   // continuation
00575   Expr* resExpr;
00576   switch (access_type) {
00577     case ArrayAtNode::byte_at       : // fall through
00578     case ArrayAtNode::double_byte_at: resExpr = new KlassExpr(Universe::smiKlassObj(), resPReg, at);            break;
00579     case ArrayAtNode::character_at  : resExpr = new KlassExpr(Universe::characterKlassObj(), resPReg, at);      break;
00580     case ArrayAtNode::object_at     : resExpr = new UnknownExpr(resPReg, at);                                   break;
00581     default                         : ShouldNotReachHere();
00582   }
00583   if (at->canFail()) {
00584     if (shouldUseUncommonTrap()) {
00585       // uncommon branch instead of failure code
00586       at->append(1, NodeFactory::new_UncommonNode(_gen->copyCurrentExprStack(), _bci /*_failure_block->begin_bci()*/));
00587     } else {
00588       // append failure code
00589       NopNode* err = NodeFactory::new_NopNode();
00590       at->append(1, err);
00591       Expr* errExpr = new KlassExpr(Universe::symbolKlassObj(), errPReg, at);
00592       resExpr = merge_failure_block(at, resExpr, err, errExpr, false);
00593     }
00594   }
00595   return resExpr;
00596 }
00597 
00598 
00599 Expr* PrimInliner::array_at_put_ifFail(ArrayAtPutNode::AccessType access_type) {
00600   assert_failure_block();
00601   assert_receiver();
00602 
00603   // parameters & result registers
00604   Expr*   array      = parameter(0);
00605   Expr*   index      = parameter(1);
00606   Expr*   element    = parameter(2);
00607   SAPReg* resPReg    = new SAPReg(_scope);      // holds the result if primitive didn't fail
00608   SAPReg* errPReg    = new SAPReg(_scope);      // holds the error message if primitive failed
00609   Klass*  klass      = array->klass()->klass_part();
00610   int     lenOffs    = klass->non_indexable_size();
00611   int     arrOffs    = lenOffs + 1;
00612   bool    storeCheck = (access_type == ArrayAtPutNode::object_at_put) && element->needsStoreCheck();
00613   
00614   if (access_type == ArrayAtPutNode::object_at_put) {
00615     // make sure blocks stored into array are created
00616     _gen->materialize(element->preg(), NULL);
00617   }
00618 
00619   // atPut node
00620   ArrayAtPutNode* atPut = NodeFactory::new_ArrayAtPutNode(
00621     access_type, array->preg(), index->preg(), index->is_smi(), element->preg(), element->is_smi(), NULL, errPReg, arrOffs, lenOffs, storeCheck
00622   );
00623   _gen->append(atPut);
00624 
00625   // continuation
00626   Expr* resExpr = array;
00627   if (atPut->canFail()) {
00628     if (shouldUseUncommonTrap()) {
00629       // uncommon branch instead of failure code
00630       atPut->append(1, NodeFactory::new_UncommonNode(_gen->copyCurrentExprStack(), _bci /*_failure_block->begin_bci()*/));
00631     } else {
00632       // append failure code
00633       NopNode* err = NodeFactory::new_NopNode();
00634       atPut->append(1, err);
00635       Expr* errExpr = new KlassExpr(Universe::symbolKlassObj(), errPReg, atPut);
00636       resExpr = merge_failure_block(atPut, resExpr, err, errExpr, true);
00637     }
00638   }
00639   return resExpr;
00640 }
00641 
00642 
00643 Expr* PrimInliner::obj_new() {
00644   // replace generic allocation primitive by size-specific primitive, if possible
00645   Expr* rcvr = parameter(0);
00646   if (!rcvr->isConstantExpr() || !rcvr->constant()->is_klass()) return NULL;
00647   Klass* klass = klassOop(rcvr->constant())->klass_part();      // class being instantiated
00648   if (klass->oop_is_indexable()) return NULL;                   // would fail (extremely unlikely)
00649   int size = klass->non_indexable_size();                       // size in words
00650 
00651   if (klass->can_inline_allocation()) {
00652     // These special compiler primitives only work for memOop klasses
00653     int number_of_instance_variables = size - memOopDesc::header_size();
00654     switch (number_of_instance_variables) {
00655       case 0: _pdesc = primitives::new0(); break;
00656       case 1: _pdesc = primitives::new1(); break;
00657       case 2: _pdesc = primitives::new2(); break;
00658       case 3: _pdesc = primitives::new3(); break;
00659       case 4: _pdesc = primitives::new4(); break;
00660       case 5: _pdesc = primitives::new5(); break;
00661       case 6: _pdesc = primitives::new6(); break;
00662       case 7: _pdesc = primitives::new7(); break;
00663       case 8: _pdesc = primitives::new8(); break;
00664       case 9: _pdesc = primitives::new9(); break;
00665       default:  ; // use generic primitives
00666     }
00667   }
00668   Expr* u = genCall(false);
00669   return new KlassExpr(klass->as_klassOop(), u->preg(), u->node());
00670 }
00671 
00672 
00673 Expr* PrimInliner::obj_shallowCopy() {
00674   // temporary hack, fix when prims have type info
00675   // Fix this Robert, 10/24-95, Lars
00676   Expr* u = genCall(false);
00677   assert(u->isUnknownExpr(), "oops");
00678   return new KlassExpr(parameter(0)->klass(), u->preg(), u->node());
00679 }
00680 
00681 
00682 Expr* PrimInliner::obj_equal() {
00683   assert_no_failure_block();
00684 
00685   // parameters & result registers
00686   PReg* arg1 = parameter(0)->preg();
00687   PReg* arg2 = parameter(1)->preg();
00688   // comparison
00689   _gen->append(NodeFactory::new_ArithRRNode(new NoPReg(_scope), arg1, CmpArithOp, arg2));
00690   SAPReg* resPReg = new SAPReg(_scope);
00691   return generate_cond(EQBranchOp, _gen, resPReg);
00692 }
00693 
00694 
00695 Expr* PrimInliner::obj_class(bool has_receiver) {
00696   assert_no_failure_block();
00697   if (has_receiver) assert_receiver();
00698 
00699   Expr*   obj     = parameter(0);
00700   if (obj->hasKlass()) {
00701     // constant-fold it
00702     klassOop k = obj->klass();
00703     return new ConstantExpr(k, new_ConstPReg(_scope, k), NULL);
00704   } else {
00705     SAPReg* resPReg = new SAPReg(_scope);
00706     InlinedPrimitiveNode* n = NodeFactory::new_InlinedPrimitiveNode(
00707       InlinedPrimitiveNode::obj_klass, resPReg, NULL, obj->preg()
00708     );
00709     _gen->append(n);
00710     // don't know exactly what it is - just use PIC info
00711     return new UnknownExpr(resPReg, n);
00712   }
00713 }
00714 
00715 
00716 Expr* PrimInliner::obj_hash(bool has_receiver) {
00717   assert_no_failure_block();
00718   if (has_receiver) assert_receiver();
00719 
00720   Expr* obj = parameter(0);
00721   if (obj->is_smi()) {
00722     // hash value = self (no code necessary)
00723     return obj;
00724   } else {
00725     return NULL;
00726     //
00727     // code in x86_node.cpp not yet implemented - fix this at some point
00728     //
00729     // has value taken from header field
00730     SAPReg* resPReg = new SAPReg(_scope);
00731     InlinedPrimitiveNode* n = NodeFactory::new_InlinedPrimitiveNode(
00732       InlinedPrimitiveNode::obj_hash, resPReg, NULL, obj->preg()
00733     );
00734     _gen->append(n);
00735     return new KlassExpr(Universe::smiKlassObj(), resPReg, n);
00736   }
00737 }
00738 
00739 
00740 Expr* PrimInliner::proxy_byte_at() {
00741   assert_failure_block();
00742   assert_receiver();
00743 
00744   // parameters & result registers
00745   Expr*   proxy     = parameter(0);
00746   Expr*   index     = parameter(1);
00747   SAPReg* resPReg   = new SAPReg(_scope);       // holds the result if primitive didn't fail
00748   SAPReg* errPReg   = new SAPReg(_scope);       // holds the error message if primitive failed
00749   
00750   // at node
00751   InlinedPrimitiveNode* at = NodeFactory::new_InlinedPrimitiveNode(
00752     InlinedPrimitiveNode::proxy_byte_at, resPReg, errPReg, proxy->preg(), index->preg(), index->is_smi()
00753   );
00754   _gen->append(at);
00755 
00756   // continuation
00757   Expr* resExpr = new KlassExpr(Universe::smiKlassObj(), resPReg, at);
00758   if (at->canFail()) {
00759     if (shouldUseUncommonTrap()) {
00760       // uncommon branch instead of failure code
00761       at->append(1, NodeFactory::new_UncommonNode(_gen->copyCurrentExprStack(), _bci /*_failure_block->begin_bci()*/));
00762     } else {
00763       // append failure code
00764       NopNode* err = NodeFactory::new_NopNode();
00765       at->append(1, err);
00766       Expr* errExpr = new KlassExpr(Universe::symbolKlassObj(), errPReg, at);
00767       resExpr = merge_failure_block(at, resExpr, err, errExpr, false);
00768     }
00769   }
00770   return resExpr;
00771 }
00772 
00773 
00774 Expr* PrimInliner::proxy_byte_at_put() {
00775   assert_failure_block();
00776   assert_receiver();
00777 
00778   // parameters & result registers
00779   Expr*   proxy     = parameter(0);
00780   Expr*   index     = parameter(1);
00781   Expr*   value     = parameter(2);
00782   SAPReg* errPReg   = new SAPReg(_scope);       // holds the error message if primitive failed
00783   
00784   // atPut node
00785   InlinedPrimitiveNode* atPut = NodeFactory::new_InlinedPrimitiveNode(
00786     InlinedPrimitiveNode::proxy_byte_at_put, NULL, errPReg, proxy->preg(), index->preg(), index->is_smi(), value->preg(), value->is_smi()
00787   );
00788   _gen->append(atPut);
00789 
00790   // continuation
00791   Expr* resExpr = proxy;
00792   if (atPut->canFail()) {
00793     if (shouldUseUncommonTrap()) {
00794       // uncommon branch instead of failure code
00795       atPut->append(1, NodeFactory::new_UncommonNode(_gen->copyCurrentExprStack(), _bci /*_failure_block->begin_bci()*/));
00796     } else {
00797       // append failure code
00798       NopNode* err = NodeFactory::new_NopNode();
00799       atPut->append(1, err);
00800       Expr* errExpr = new KlassExpr(Universe::symbolKlassObj(), errPReg, atPut);
00801       resExpr = merge_failure_block(atPut, resExpr, err, errExpr, true);
00802     }
00803   }
00804   return resExpr;
00805 }
00806 
00807 
00808 Expr* PrimInliner::block_primitiveValue() {
00809   PReg* r = parameter(0)->preg();
00810   if (r->isBlockPReg()) {
00811     // we know the identity of the block -- inline it if possible
00812     Inliner* inliner = _gen->inliner();
00813     SendInfo* info = new SendInfo(_scope, parameter(0), _pdesc->selector());
00814     Expr* res = inliner->inlineBlockInvocation(info);
00815     if (res) return res;
00816   } 
00817   // could at least inline block invocation -- fix this later
00818   return NULL;
00819 }
00820 
00821 
00822 Expr* PrimInliner::tryInline() {
00823   // Returns the failure result or the result of the primitive (if the
00824   // primitive can't fail) if the primitive has been inlined; returns
00825   // NULL otherwise. If the primitive has been inlined but can't fail,
00826   // the bci in the MethodDecoder is set to the first instruction after
00827   // the failure block.
00828   // NB: The comparisons below should be replaced with pointer comparisons
00829   // comparing with the appropriate vmSymbol. Should fix this at some point.
00830   char* name  = _pdesc->name();
00831   Expr* res = NULL;
00832   switch (_pdesc->group()) {
00833     case IntArithmeticPrimitive:
00834       if (number_of_parameters() == 2) {
00835         Expr* x = parameter(0);
00836         Expr* y = parameter(1);
00837         if (equal(name, "primitiveAdd:ifFail:"))                        { res = smi_ArithmeticOp(tAddArithOp, x, y);    break; }
00838         if (equal(name, "primitiveSubtract:ifFail:"))                   { res = smi_ArithmeticOp(tSubArithOp, x, y);    break; }
00839         if (equal(name, "primitiveMultiply:ifFail:"))                   { res = smi_ArithmeticOp(tMulArithOp, x, y);    break; }
00840         if (equal(name, "primitiveDiv:ifFail:"))                        { res = smi_Div(x, y);                          break; }
00841         if (equal(name, "primitiveMod:ifFail:"))                        { res = smi_Mod(x, y);                          break; }
00842         if (equal(name, "primitiveBitAnd:ifFail:"))                     { res = smi_BitOp(tAndArithOp, x, y);           break; }
00843         if (equal(name, "primitiveBitOr:ifFail:"))                      { res = smi_BitOp(tOrArithOp , x, y);           break; }
00844         if (equal(name, "primitiveBitXor:ifFail:"))                     { res = smi_BitOp(tXOrArithOp, x, y);           break; }
00845         if (equal(name, "primitiveRawBitShift:ifFail:"))                { res = smi_Shift(x, y);                        break; }
00846       }
00847       break;
00848     case IntComparisonPrimitive:
00849       if (number_of_parameters() == 2) {
00850         Expr* x = parameter(0);
00851         Expr* y = parameter(1);
00852         if (equal(name, "primitiveSmallIntegerEqual:ifFail:"))          { res = smi_Comparison(EQBranchOp, x, y);       break; }
00853         if (equal(name, "primitiveSmallIntegerNotEqual:ifFail:"))       { res = smi_Comparison(NEBranchOp, x, y);       break; }
00854         if (equal(name, "primitiveLessThan:ifFail:"))                   { res = smi_Comparison(LTBranchOp, x, y);       break; }
00855         if (equal(name, "primitiveLessThanOrEqual:ifFail:"))            { res = smi_Comparison(LEBranchOp, x, y);       break; }
00856         if (equal(name, "primitiveGreaterThan:ifFail:"))                { res = smi_Comparison(GTBranchOp, x, y);       break; }
00857         if (equal(name, "primitiveGreaterThanOrEqual:ifFail:"))         { res = smi_Comparison(GEBranchOp, x, y);       break; }
00858       }
00859       break;
00860     case FloatArithmeticPrimitive:
00861       break;
00862     case FloatComparisonPrimitive:
00863       break;
00864     case ObjArrayPrimitive:
00865       if (equal(name, "primitiveIndexedObjectSize"))                    { res = array_size();                                           break; }
00866       if (equal(name, "primitiveIndexedObjectAt:ifFail:"))              { res = array_at_ifFail(ArrayAtNode::object_at);                break; }
00867       if (equal(name, "primitiveIndexedObjectAt:put:ifFail:"))          { res = array_at_put_ifFail(ArrayAtPutNode::object_at_put);     break; }
00868       break;
00869     case ByteArrayPrimitive:
00870       if (equal(name, "primitiveIndexedByteSize"))                      { res = array_size();                                           break; }
00871       if (equal(name, "primitiveIndexedByteAt:ifFail:"))                { res = array_at_ifFail(ArrayAtNode::byte_at);                  break; }
00872       if (equal(name, "primitiveIndexedByteAt:put:ifFail:"))            { res = array_at_put_ifFail(ArrayAtPutNode::byte_at_put);       break; }
00873       break;
00874     case DoubleByteArrayPrimitive:
00875       if (equal(name, "primitiveIndexedDoubleByteSize"))                { res = array_size();                                           break; }
00876       if (equal(name, "primitiveIndexedDoubleByteAt:ifFail:"))          { res = array_at_ifFail(ArrayAtNode::double_byte_at);           break; }
00877       if (equal(name, "primitiveIndexedDoubleByteCharacterAt:ifFail:")) { res = array_at_ifFail(ArrayAtNode::character_at);             break; }
00878       if (equal(name, "primitiveIndexedDoubleByteAt:put:ifFail:"))      { res = array_at_put_ifFail(ArrayAtPutNode::double_byte_at_put);break; }
00879       break;
00880     case BlockPrimitive:
00881       if (strncmp(name, "primitiveValue", 14) == 0)                     { res = block_primitiveValue();         break; }
00882       break;
00883     case NormalPrimitive:
00884       if (strncmp(name, "primitiveNew", 12) == 0)                       { res = obj_new();                      break; }
00885       if (equal(name, "primitiveShallowCopyIfFail:ifFail:"))            { res = obj_shallowCopy();              break; }
00886       if (equal(name, "primitiveEqual:"))                               { res = obj_equal();                    break; }
00887       if (equal(name, "primitiveClass"))                                { res = obj_class(true);                break; }
00888       if (equal(name, "primitiveClassOf:"))                             { res = obj_class(false);               break; }
00889       if (equal(name, "primitiveHash"))                                 { res = obj_hash(true);                 break; }
00890       if (equal(name, "primitiveHashOf:"))                              { res = obj_hash(false);                break; }
00891       if (equal(name, "primitiveProxyByteAt:ifFail:"))                  { res = proxy_byte_at();                break; }
00892       if (equal(name, "primitiveProxyByteAt:put:ifFail:"))              { res = proxy_byte_at_put();            break; }
00893       break;
00894    default:
00895       fatal1("bad primitive group %d", _pdesc->group());
00896       break;
00897   }
00898  
00899   if (CompilerDebug) {
00900     cout(PrintInlining && (res != NULL))->print("%*sinlining %s %s\n", _scope->depth + 2, "", _pdesc->name(),
00901                                                 _usingUncommonTrap ? "(unc. failure)" : (_cannotFail ? "(cannot fail)" :  ""));
00902   }
00903   if (!_usingUncommonTrap && !_cannotFail) theCompiler->reporter->report_prim_failure(_pdesc);
00904   return res;
00905 }
00906 
00907 
00908 PrimInliner::PrimInliner(NodeBuilder* gen, primitive_desc* pdesc, MethodInterval* failure_block) {
00909   assert(pdesc, "must have a primitive desc to inline");
00910   _gen          = gen;
00911   _pdesc        = pdesc;
00912   _failure_block= failure_block;
00913 
00914   _scope        = gen->_scope;
00915   _bci          = gen->bci();     // bci of primitive call
00916   _exprStack    = gen->_exprStack;
00917   _cannotFail   = true;
00918   _params       = new GrowableArray<Expr*>(number_of_parameters(), number_of_parameters(), NULL);
00919   _usingUncommonTrap = false;
00920 
00921   // get parameters
00922   int i = number_of_parameters();
00923   int first = _exprStack->length() - i;
00924   while (i-- > 0) {
00925     _params->at_put(i, _exprStack->at(first + i));
00926   }
00927 
00928   assert(_pdesc->can_fail() == (failure_block != NULL), "primitive desc & primitive usage inconsistent");
00929 }
00930 
00931 
00932 void PrimInliner::generate() {
00933   Expr* res = NULL;
00934   if (InlinePrims) { 
00935     if (ConstantFoldPrims) { res = tryConstantFold(); }
00936     if (res == NULL)       { res = tryTypeCheck(); }
00937     if (res == NULL)       { res = tryInline(); }
00938   }
00939   if (res == NULL) {
00940     // primitive has not been constant-folded nor inlined
00941     // -> must call primitive at run-time
00942     res = genCall(_pdesc->can_fail());
00943   }
00944   assert(res, "must have result expr");
00945   _exprStack->pop(_pdesc->number_of_parameters());      // pop parameters
00946   _exprStack->push2nd(res, _scope, _bci);               // push primitive result
00947 }
00948 
00949 
00950 Expr* PrimInliner::genCall(bool canFail) {
00951   // standard primitive call
00952   //
00953   // Note: If a primitive fails, it will return a marked symbol. One has to make sure that
00954   //       this marked symbol is *never* stored on the stack but only kept in registers
00955   //       (otherwise GC won't work correctly). Here this is established by using the dst()
00956   //       of a pcall only which is pre-allocated to the result_reg.
00957 
00958   MergeNode*            nlrTestPoint    = _pdesc->can_perform_NLR() ? _scope->nlrTestPoint() : NULL;
00959   GrowableArray<PReg*>* args            = _gen->pass_arguments(NULL, _pdesc->number_of_parameters());
00960   GrowableArray<PReg*>* exprStack       = _pdesc->can_walk_stack() ? _gen->copyCurrentExprStack() : NULL;
00961   PrimNode*             pcall           = NodeFactory::new_PrimNode(_pdesc, nlrTestPoint, args, exprStack);
00962 
00963   _gen->append(pcall);
00964 
00965   BranchNode* branch = NULL;
00966   if (_failure_block != NULL && canFail) {
00967     // primitive with failure block; failed if Mark_Tag_Bit is set in result -> add a branch node here
00968     _gen->append(NodeFactory::new_ArithRCNode(new NoPReg(_scope), pcall->dest(), TestArithOp, Mark_Tag_Bit)); 
00969     branch = NodeFactory::new_BranchNode(NEBranchOp);
00970     _gen->append(branch);
00971   }
00972 
00973   // primitive didn't fail (with or without failure block) -> assign to resPReg & determine its expression
00974   SAPReg* resPReg = new SAPReg(_scope);
00975   _gen->append(NodeFactory::new_AssignNode(pcall->dst(), resPReg));
00976   Node* ok_exit = _gen->_current;
00977   Expr* resExpr = _pdesc->return_klass(resPReg, ok_exit);
00978   if (resExpr == NULL) resExpr = new UnknownExpr(resPReg, ok_exit);
00979 
00980   if (branch != NULL) {
00981     // add failure block if primitive can fail -> reset Mark_Tag_Bit first
00982     SAPReg* errPReg = new SAPReg(_scope);
00983     ArithRCNode* failure_exit = NodeFactory::new_ArithRCNode(errPReg, pcall->dst(), AndArithOp, ~Mark_Tag_Bit);
00984     branch->append(1, failure_exit);
00985     resExpr = merge_failure_block(ok_exit, resExpr, failure_exit, new KlassExpr(Universe::symbolKlassObj(), errPReg, failure_exit), false);
00986   }
00987 
00988   return resExpr;
00989 }
00990 
00991 
00992 void PrimInliner::print() {
00993   std->print("a PrimInliner\n");
00994 }
00995 
00996 
00997 # endif

Generated on Mon Oct 9 13:37:23 2006 for Strongtalk VM by  doxygen 1.4.7