nodeBuilder.cpp

Go to the documentation of this file.
00001 /* Copyright 1994 - 1996 LongView Technologies L.L.C. $Revision: 1.77 $ */
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/_nodeBuilder.cpp.incl"
00028 
00029 // Class variables
00030 
00031 Node* NodeBuilder::EndOfCode = (Node*)-1;
00032 
00033 
00034 // Initialization
00035 
00036 NodeBuilder::NodeBuilder() {
00037   _exprStack = NULL;
00038   _inliner   = NULL;
00039   _scope     = NULL;
00040   _current   = NULL;
00041 }
00042 
00043 
00044 void NodeBuilder::initialize(InlinedScope* scope) {
00045   _exprStack = new ExprStack(scope, 8);
00046   _inliner   = new Inliner(scope);
00047   _scope     = scope;
00048   _current   = NULL;
00049 }
00050 
00051 
00052 // Helper functions for node creation/concatenation
00053 
00054 void NodeBuilder::append(Node* node) { 
00055   if (node->isExitNode()) warning("should use append_exit for consistency");
00056   if (aborting() || _current == EndOfCode) {
00057     if (node->nPredecessors() == 0) {
00058       // ignore this code 
00059       // (sometimes, the bytecode compiler generates dead code after returns)
00060     } else {
00061       // node is already connected to graph (merge node), so restart code generation 
00062       _current = node;
00063     }
00064   } else {
00065     _current = _current->append(node); 
00066   }
00067 }
00068 
00069 
00070 void NodeBuilder::append_exit(Node* node) { 
00071   assert(node->isExitNode(), "not an exit node");
00072   if (_current != EndOfCode) _current->append(node);
00073   _current = NULL;
00074 }
00075 
00076 
00077 void NodeBuilder::branch(MergeNode* target) {
00078   // connect current with target
00079   if (_current != NULL && _current != EndOfCode && _current != target) {
00080     _current->append(target);
00081   }
00082   _current = target;
00083 }
00084 
00085 
00086 void NodeBuilder::comment(char* s) {
00087   if (CompilerDebug) append(NodeFactory::new_CommentNode(s));
00088 }
00089 
00090 
00091 GrowableArray<PReg*>* NodeBuilder::copyCurrentExprStack() {
00092   int l = exprStack()->length();
00093   GrowableArray<PReg*>* es = new GrowableArray<PReg*>(l);
00094   for (int i = 0; i < l; i++) {
00095     es->push(exprStack()->at(i)->preg());
00096   }
00097   return es;
00098 }
00099 
00100 
00101 // Node creation
00102 
00103 void NodeBuilder::abort() {
00104   MethodClosure::abort();
00105   _current = EndOfCode;
00106 }
00107 
00108 bool NodeBuilder::abortIfDead(Expr* e) {
00109   if (e->isNoResultExpr()) {
00110     // dead code
00111     abort();
00112     return true;
00113   } else {
00114     return false;
00115   }
00116 }
00117 
00118 // Caution: do not use MethodIterator directly, always go through this function.
00119 // Otherwise, things will break in the presence of dead code.
00120 // Also, after calling generate_subinterval, make sure you set current (since
00121 // the subinterval may have ended dead, leaving current at EndOfCode).
00122 void NodeBuilder::generate_subinterval(MethodInterval* m, bool produces_result) {
00123   assert(!aborting(), "shouldn't generate when already aborting");
00124   int savedLen = exprStack()->length();
00125   MethodIterator mi(m, this);
00126   if (aborting()) {
00127     // the subinterval ended with dead code
00128     Expr* res = exprStack()->isEmpty() ? NULL : exprStack()->top();
00129     assert(res == NULL || res->isNoResultExpr(), "expected no result");
00130     un_abort();   // abort will be done by caller (if needed)
00131     int diff = exprStack()->length() - savedLen;
00132     if (produces_result) diff--;
00133     if (diff > 0) {
00134       // adjust expression stack top pop extra stuff
00135       exprStack()->pop(diff);
00136     }
00137     if (produces_result) {
00138       if (res == NULL) {
00139         // subinterval should have produced a result but didn't
00140         // This is legal: e.g., in "someCond or: [ otherCond ifTrue: [^ false ]. true]" the subinterval
00141         // of or: doesn't return a result if otherCond is known to be true.   So, just fix it here.
00142         // Urs 9/6/96
00143         res = new NoResultExpr();
00144         exprStack()->push(res, scope(), m->end_bci());
00145       } else {
00146         exprStack()->assign_top(res);
00147       }
00148     }
00149   }
00150 }
00151 
00152 
00153 void NodeBuilder::constant_if_node(IfNode* node, ConstantExpr* cond) {
00154   // if statement with constant condition
00155   oop c = cond->constant();
00156   int resultBCI = node->begin_bci();
00157   if (c == trueObj || c == falseObj) {
00158     if (node->is_ifTrue() == (c == trueObj)) {
00159       // then branch is always taken
00160       generate_subinterval(node->then_code(), node->produces_result());
00161     } else if (node->else_code() != NULL) {
00162       // else branch always taken
00163       generate_subinterval(node->else_code(), node->produces_result());
00164     } else {
00165       // branch is never executed -> ignore
00166     }
00167     if (node->produces_result()) {
00168       Expr* res = exprStack()->top();
00169       // materialize(res, NULL);
00170       // NB: need not materialize block because it isn't merged with else branch
00171       // (BlockPReg will be materialized when assigned)
00172       scope()->setExprForBCI(resultBCI, res);     // for debugging info
00173       assert(!res->isNoResultExpr() || is_in_dead_code(), "no result should imply in_dead_code");
00174       abortIfDead(res);                           // constant if ends dead, so method ends dead
00175     } else {
00176       if (is_in_dead_code()) abort();             // constant if ends dead, so method ends dead
00177     }
00178   } else {
00179     // non-boolean condition -> fails always
00180     append(NodeFactory::new_UncommonNode(copyCurrentExprStack(), resultBCI));
00181   }
00182 }
00183 
00184 
00185 TypeTestNode* NodeBuilder::makeTestNode(bool cond, PReg* r) {
00186   GrowableArray<klassOop>* list = new GrowableArray<klassOop>(2);
00187   if (cond) {
00188     list->append(trueObj->klass());
00189     list->append(falseObj->klass());
00190   } else {
00191     list->append(falseObj->klass());
00192     list->append(trueObj->klass());
00193   }
00194   TypeTestNode* test = NodeFactory::new_TypeTestNode(r, list, true);
00195   test->append(0, NodeFactory::new_UncommonNode(copyCurrentExprStack(), bci()));
00196   return test;
00197 }
00198 
00199 
00200 void NodeBuilder::if_node(IfNode* node) {
00201   Expr* cond = exprStack()->pop();
00202   int resultBCI = node->begin_bci();
00203   if (abortIfDead(cond)) {
00204     if (node->produces_result()) exprStack()->push(cond, scope(), resultBCI);
00205     return;
00206   }
00207   if (cond->isConstantExpr()) {
00208     constant_if_node(node, (ConstantExpr*)cond);
00209   } else {
00210     // non-constant condition
00211     TypeTestNode* test = makeTestNode(node->is_ifTrue(), cond->preg());
00212     append(test);
00213     if (node->else_code() != NULL) {
00214       // with else branch
00215       Expr*      ifResult   = NULL;
00216       Expr*      elseResult = NULL;
00217       SAPReg*    resultReg  = new SAPReg(scope());
00218       MergeNode* ifBranch   = NodeFactory::new_MergeNode(node->then_code()->begin_bci());
00219       MergeNode* elseBranch = NodeFactory::new_MergeNode(node->else_code()->begin_bci());
00220       MergeNode* endOfIf    = NodeFactory::new_MergeNode(node->end_bci());
00221       test->append(1, ifBranch);
00222       test->append(2, elseBranch);
00223       splitMergeExpr(cond, test);
00224       // then branch
00225       setCurrent(ifBranch);
00226       generate_subinterval(node->then_code(), node->produces_result());
00227       bool ifEndsDead = is_in_dead_code();
00228       if (node->produces_result()) {
00229         ifResult = exprStack()->pop();
00230         if (!ifResult->isNoResultExpr()) {
00231           // NB: must materialize block because it is merged with result of else branch
00232           // (was bug 7/4/96 -Urs)
00233           materialize(ifResult->preg(), NULL);
00234           append(NodeFactory::new_AssignNode(ifResult->preg(), resultReg));
00235         } else {
00236           assert(ifEndsDead, "oops");
00237         }
00238       }
00239       append(endOfIf);
00240       // else branch
00241       setCurrent(elseBranch);
00242       generate_subinterval(node->else_code(), node->produces_result());
00243       bool elseEndsDead = is_in_dead_code();
00244       if (node->produces_result()) {
00245         elseResult = exprStack()->pop();
00246         if (!elseResult->isNoResultExpr()) {
00247           materialize(elseResult->preg(), NULL);
00248           append(NodeFactory::new_AssignNode(elseResult->preg(), resultReg));
00249         } else {
00250           assert(elseEndsDead, "oops");
00251         }
00252       }
00253       append(endOfIf);
00254       setCurrent(endOfIf);
00255       // end
00256       if (ifEndsDead && elseEndsDead) {
00257         abort();      // both branches end dead, so containing interval ends dead
00258       } else {
00259         if (node->produces_result()) {
00260           exprStack()->push2nd(new MergeExpr(ifResult, elseResult, resultReg, current()), scope(), resultBCI);
00261         }
00262       }
00263     } else {
00264       // no else branch
00265       assert(!node->produces_result(), "inconsistency - else branch required");
00266       MergeNode* ifBranch   = NodeFactory::new_MergeNode(node->then_code()->begin_bci());
00267       MergeNode* endOfIf    = NodeFactory::new_MergeNode(node->end_bci());
00268       test->append(1, ifBranch);
00269       test->append(2, endOfIf);
00270       splitMergeExpr(cond, test);
00271       // then branch
00272       setCurrent(ifBranch);
00273       generate_subinterval(node->then_code(), false);
00274       append(endOfIf);
00275       setCurrent(endOfIf);
00276       if (node->produces_result()) {
00277         // materialize(exprStack()->top(), NULL);
00278         // noo need to materialize result (see commment in constant_if_code)
00279         scope()->setExprForBCI(resultBCI, exprStack()->top());    // for debugging info
00280       }
00281     }
00282     comment("end of if");
00283   }
00284 }
00285 
00286 
00287 void NodeBuilder::cond_node(CondNode* node) {
00288   Expr* cond = exprStack()->pop();
00289   int resultBCI = node->begin_bci();
00290   if (abortIfDead(cond)) {
00291     exprStack()->push(cond, scope(), resultBCI);
00292     return;         // condition ends dead, so rest of code does, too
00293   }
00294   if (cond->isConstantExpr()) {
00295     // constant condition
00296     oop c = cond->asConstantExpr()->constant();
00297     if (c == trueObj || c == falseObj) {
00298       if (node->is_and() && c == trueObj ||
00299           node->is_or()  && c == falseObj) {
00300         generate_subinterval(node->expr_code(), true);
00301         // result of and:/or: is result of 2nd expression
00302         Expr* res = exprStack()->top();
00303         scope()->setExprForBCI(resultBCI, res);   // for debugging info
00304         if (abortIfDead(res)) return;             // 2nd expr never returns, so rest is dead
00305       } else {
00306         // don't need to evaluate 2nd expression, result is cond
00307         exprStack()->push(cond, scope(), resultBCI);
00308       }
00309     } else {
00310       // non-boolean condition -> fails always
00311       append(NodeFactory::new_UncommonNode(copyCurrentExprStack(), resultBCI));
00312     }
00313   } else {
00314     // non-constant condition
00315     SAPReg* resultReg  = new SAPReg(scope());
00316     TypeTestNode* test = makeTestNode(node->is_and(), cond->preg());
00317     append(test);
00318     MergeNode* condExpr   = NodeFactory::new_MergeNode(node->expr_code()->begin_bci());
00319     MergeNode* otherwise  = NodeFactory::new_MergeNode(node->expr_code()->begin_bci());
00320     MergeNode* endOfCond  = NodeFactory::new_MergeNode(node->end_bci());
00321     test->append(1, condExpr);
00322     test->append(2, otherwise);
00323     setCurrent(otherwise);
00324     append(NodeFactory::new_AssignNode(cond->preg(), resultReg));
00325     append(endOfCond);
00326     splitMergeExpr(cond, test);     // split on result of first expression
00327     // evaluate second conditional expression
00328     setCurrent(condExpr);
00329     generate_subinterval(node->expr_code(), true);
00330     Expr* condResult = exprStack()->pop();
00331     if (condResult->isNoResultExpr()) {
00332       exprStack()->push2nd(new NoResultExpr, scope(), resultBCI);       // dead code
00333       setCurrent(endOfCond);
00334     } else {
00335       append(NodeFactory::new_AssignNode(condResult->preg(), resultReg));
00336       append(endOfCond);
00337       setCurrent(endOfCond);
00338       // end
00339       // The result of the conditional is *one* branch of the first expression (cond) plus
00340       // the result of the second expression.  (Was splitting bug -- Urs 4/96)
00341       Expr* exclude = cond->findKlass(node->is_or() ? falseObj->klass() : trueObj->klass());
00342       Expr* first;
00343       if (exclude) {
00344         first = cond->copyWithout(exclude);
00345       } else {
00346         first = cond;
00347       }
00348       exprStack()->push2nd(new MergeExpr(first, condResult, resultReg, current()), scope(), resultBCI);
00349       comment("end of cond");
00350     }
00351   }
00352 }
00353 
00354 
00355 void NodeBuilder::while_node(WhileNode* node) {
00356   int loop_bci = node->body_code() != NULL ? node->body_code()->begin_bci() : node->expr_code()->begin_bci();
00357   CompiledLoop* wloop = _scope->addLoop();
00358   LoopHeaderNode* header = NodeFactory::new_LoopHeaderNode();
00359   append(header);
00360   wloop->set_startOfLoop(header);
00361   MergeNode* loop = NodeFactory::new_MergeNode(loop_bci);
00362   MergeNode* exit = NodeFactory::new_MergeNode(node->end_bci());
00363   MergeNode* entry= NULL;       // entry point into loop (start of condition)
00364   exit->isLoopEnd = true;
00365   if (node->body_code() != NULL) {
00366     // set up entry point
00367     entry = NodeFactory::new_MergeNode(node->expr_code()->begin_bci());
00368     append(entry);
00369     entry->isLoopStart = true;
00370   } else {
00371     // no body code -> start with conditional expression
00372     append(loop);
00373     loop->isLoopStart = true;
00374   }
00375   wloop->set_startOfCond(current());
00376   generate_subinterval(node->expr_code(), true);
00377   Expr* cond = exprStack()->pop();
00378   if (abortIfDead(cond)) {
00379     return;       // condition ends dead --> loop is never executed
00380   }
00381   if (false && cond->isConstantExpr()) {
00382     wloop->set_endOfCond(current());
00383     // ^^^ TURNED OFF - doesn't work for endless loops yet - FIX THIS
00384     // constant condition
00385     oop c = cond->asConstantExpr()->constant();
00386     if (c == trueObj || c == falseObj) {
00387       if (node->is_whileTrue() == (c == trueObj)) {
00388         append(loop);
00389         setCurrent(exit);
00390       }
00391     } else {
00392       // non-boolean condition -> fails always
00393       append(NodeFactory::new_UncommonNode(copyCurrentExprStack(), bci()));
00394     }
00395   } else {
00396     // non-constant condition
00397     TypeTestNode* test = makeTestNode(node->is_whileTrue(), cond->preg());
00398     append(test);
00399     wloop->set_endOfCond(test);
00400     test->append(1, loop);
00401     test->append(2, exit);
00402     setCurrent(exit);
00403     splitMergeExpr(cond, test);
00404     comment("end of while");
00405   }
00406 
00407   if (node->body_code() != NULL) {
00408     // generate loop body 
00409     // NB: *must* be done after generating condition, because Node order must correspond to
00410     // bci order, otherwise copy propagation breaks  -Urs 10/95
00411     Node* curr = current();
00412     setCurrent(loop);
00413     generate_subinterval(node->body_code(), false);
00414     wloop->set_startOfBody(loop->next());   // don't use loop (MergeNode) as start since it's been 
00415                                             // created too early (before loop cond) --> node id range is off
00416     if (theCompiler->is_uncommon_compile()) {
00417       // Make sure the invocation counter is incremented at least once per iteration; otherwise uncommon 
00418       // nmethods containing loops but no sends won't be recompiled early enough. 
00419       append(NodeFactory::new_FixedCodeNode(FixedCodeNode::inc_counter));
00420     }
00421     wloop->set_endOfBody(current());
00422     append(entry);
00423     setCurrent(curr);
00424   }
00425   wloop->set_endOfLoop(exit);
00426 }
00427 
00428 
00429 void NodeBuilder::primitive_call_node(PrimitiveCallNode* node) {
00430   if (node->pdesc() == NULL) {
00431     error("calling unknown primitive");
00432     exprStack()->pop();
00433     return;
00434   } 
00435   PrimInliner* p = new PrimInliner(this, node->pdesc(), node->failure_code());
00436   p->generate();
00437 }
00438 
00439 
00440 void NodeBuilder::dll_call_node(DLLCallNode* node) {
00441   GrowableArray<PReg*>* args = pass_arguments(NULL, node->nofArgs());
00442   assert(node->failure_code() == NULL, "compiler cannot handle DLL calls with failure blocks yet");
00443   DLLNode* dcall = NodeFactory::new_DLLNode(node->dll_name(), node->function_name(), node->function(), node->async(), scope()->nlrTestPoint(), args, copyCurrentExprStack());
00444   append(dcall);
00445   exprStack()->pop(node->nofArgs());
00446   // a proxy object has been pushed before the arguments, assign result
00447   // to its _pointer field - the proxy is also the result of the dll call
00448   // (since the result is NOT a Delta pointer, no store check is needed)
00449   append(NodeFactory::new_StoreOffsetNode(dcall->dest(), exprStack()->top()->preg(), pointer_no, false));
00450 }
00451 
00452 
00453 void NodeBuilder::allocate_temporaries(int nofTemps) {
00454   methodOop m = _scope->method();
00455   assert(1 + nofTemps == m->number_of_stack_temporaries(), "no. of stack variables inconsistent");
00456   // temporaries are allocated in the beginning (InlinedScope::createTemporaries)
00457 }
00458 
00459 
00460 void NodeBuilder::push_self() {
00461   exprStack()->push(scope()->self(), scope(), scope()->bci());
00462 }
00463 
00464 
00465 void NodeBuilder::push_tos() {
00466   exprStack()->push(exprStack()->top(), scope(), scope()->bci());
00467 }
00468 
00469 
00470 void NodeBuilder::push_literal(oop obj) {
00471   exprStack()->push(new ConstantExpr(obj, new_ConstPReg(_scope, obj), NULL), scope(), scope()->bci());
00472 }
00473 
00474 
00475 void NodeBuilder::push_argument(int no) {
00476   // arguments are non-assignable, so no assignment to SAPReg necessary
00477   assert((0 <= no) && (no < _scope->nofArguments()), "illegal argument no");
00478   exprStack()->push(scope()->argument(no), scope(), scope()->bci());
00479 }
00480 
00481 
00482 void NodeBuilder::push_temporary(int no) {
00483   // must assign non-parameters to temporary because exprStack entries must be singly-assigned
00484   // and because source (i.e., temporary location) could be assigned between now and the send
00485   // that actually consumes the value
00486   assert((0 <= no) && (no < _scope->nofTemporaries()), "illegal temporary no");
00487   Expr* temp = _scope->temporary(no);
00488   PReg* src = temp->preg();
00489   SAPReg* dst = new SAPReg(_scope);
00490   append(NodeFactory::new_AssignNode(src, dst));
00491   exprStack()->push(temp, scope(), scope()->bci());
00492 }
00493 
00494 
00495 void NodeBuilder::access_temporary(int no, int context, bool push) {
00496   // generates code to access temporary no in (logical, i.e., interpreter) context
00497   // context numbering starts a 0
00498   //assert(_scope->allocatesInterpretedContext() == (_contextInitializer != NULL), "context must exist already if used (find_scope)");
00499   assert(context >= 0, "context must be >= 0");
00500   int nofIndirections;
00501   OutlinedScope* out = NULL;
00502   InlinedScope* s = _scope->find_scope(context, nofIndirections, out);
00503   if (nofIndirections < 0) {
00504     // the accessed variable is in the same stack frame, in scope s
00505     if (push) {
00506       Expr* contextTemp = s->contextTemporary(no);
00507       PReg* src = contextTemp->preg();
00508       Expr* res;
00509       if (src->isBlockPReg()) {
00510         // don't copy around blocks; see ContextInitializeNode et al.
00511         res = contextTemp;
00512       } else {
00513         SAPReg* dst = new SAPReg(_scope);
00514         append(NodeFactory::new_AssignNode(src, dst));
00515         res = s->contextTemporary(no)->shallowCopy(dst, _current);
00516       }
00517       exprStack()->push(res, scope(), scope()->bci());
00518     } else {
00519       // store
00520       PReg* src = exprStack()->top()->preg();
00521       materialize(src, NULL);
00522       PReg* dst = s->contextTemporary(no)->preg();
00523       append(NodeFactory::new_AssignNode(src, dst));
00524     }
00525   } else {
00526     // the accessed variable is in higher stack frames
00527     assert(out, "must be set");
00528     assert(out->scope()->allocates_compiled_context(), "must allocate context");
00529     NameDesc* nd = out->scope()->contextTemporary(no);
00530     Location loc = nd->location();      // location of temp in compiled context
00531     assert(loc.isContextLocation(), "must be in context");
00532     int tempNo = loc.tempNo();          // compiled offset
00533     if (tempNo != no) {
00534       compiler_warning("first time this happens: compiled context offset != interpreted context offset");
00535     }
00536     if (push) {
00537       SAPReg* dst = new SAPReg(_scope);
00538       append(NodeFactory::new_LoadUplevelNode(dst, s->context(), nofIndirections, contextOopDesc::temp0_word_offset() + tempNo, NULL));
00539       exprStack()->push(new UnknownExpr(dst, _current), scope(), scope()->bci());
00540     } else {
00541       // store
00542       Expr* srcExpr = exprStack()->top();
00543       PReg* src = srcExpr->preg();
00544       materialize(src, NULL);
00545       append(NodeFactory::new_StoreUplevelNode(src, s->context(), nofIndirections, contextOopDesc::temp0_word_offset() + tempNo, NULL, srcExpr->needsStoreCheck()));
00546     }
00547   }
00548 }
00549 
00550 
00551 void NodeBuilder::push_temporary(int no, int context) {
00552   access_temporary(no, context, true);
00553 }
00554 
00555 
00556 void NodeBuilder::push_instVar(int offset) {
00557   assert(offset >= 0, "offset must be positive");
00558   SAPReg* dst = new SAPReg(_scope);
00559   PReg* base = _scope->self()->preg();
00560   append(NodeFactory::new_LoadOffsetNode(dst, base, offset, false));
00561   exprStack()->push(new UnknownExpr(dst, _current), scope(), scope()->bci());
00562 }
00563 
00564 
00565 void NodeBuilder::push_global(associationOop associationObj) {
00566   SAPReg* dst = new SAPReg(_scope);
00567   if (associationObj->is_constant()) {
00568     // constant association -- can inline the constant
00569     oop c = associationObj->value();
00570     ConstPReg* r = new_ConstPReg(_scope, c);
00571     exprStack()->push(new ConstantExpr(c, r, NULL), _scope, scope()->bci());
00572   } else {
00573     // Removed by Lars Bak, 4-22-96
00574     // if (associationObj->value()->is_klass()) 
00575     //    compiler_warning("potential performance bug: non-constant association containing klassOop");
00576     ConstPReg* base = new_ConstPReg(_scope, associationObj);
00577     append(NodeFactory::new_LoadOffsetNode(dst, base, associationOopDesc::value_offset(), false));
00578     exprStack()->push(new UnknownExpr(dst, _current), _scope, scope()->bci());
00579   }
00580 }
00581 
00582 
00583 void NodeBuilder::store_temporary(int no) {
00584   PReg* src = exprStack()->top()->preg();
00585   // should check here whether src is memoized block pushed in preceding byte code;
00586   // if so, un-memoize it  -- fix this
00587   materialize(src, NULL);
00588   PReg* dst = _scope->temporary(no)->preg();
00589   if (src != dst) append(NodeFactory::new_AssignNode(src, dst));
00590 }
00591 
00592 
00593 void NodeBuilder::store_temporary(int no, int context) {
00594   access_temporary(no, context, false);
00595 }
00596 
00597 
00598 void NodeBuilder::store_instVar(int offset) {
00599   assert(offset >= 0, "offset must be positive");
00600   Expr* srcExpr = exprStack()->top();
00601   PReg* src = srcExpr->preg();
00602   materialize(src, NULL);
00603   PReg* base = _scope->self()->preg();
00604   append(NodeFactory::new_StoreOffsetNode(src, base, offset, srcExpr->needsStoreCheck()));
00605 }
00606 
00607 
00608 void NodeBuilder::store_global(associationOop associationObj) {
00609   Expr* srcExpr = exprStack()->top();
00610   PReg* src = srcExpr->preg();
00611   materialize(src, NULL);
00612   ConstPReg* base = new_ConstPReg(_scope, associationObj);
00613   append(NodeFactory::new_StoreOffsetNode(src, base, associationOopDesc::value_offset(), srcExpr->needsStoreCheck()));
00614 }
00615 
00616 
00617 void NodeBuilder::pop() {
00618   exprStack()->pop();
00619 }
00620 
00621 
00622 // always call materialize before storing or passing a run-time value that could be a block
00623 void NodeBuilder::materialize(PReg* r, GrowableArray<BlockPReg*>* materialized) {
00624   // make sure the block (and all parent blocks / uplevel-accessed blocks) exist
00625   // materialized is a list of blocks already materialized (NULL if none)
00626   if (r->isBlockPReg() && (materialized == NULL || !materialized->contains((BlockPReg*)r))) {
00627     BlockPReg* blk = (BlockPReg*)r;
00628     append(NodeFactory::new_BlockMaterializeNode(blk, copyCurrentExprStack()));
00629     if (materialized == NULL) materialized = new GrowableArray<BlockPReg*>(5);
00630     materialized->append(blk);
00631     GrowableArray<PReg*>* reads = blk->uplevelRead();
00632     if (reads) {
00633       for (int i = reads->length() - 1; i >= 0; i--) materialize(reads->at(i), materialized);
00634     }
00635   }
00636 }
00637 
00638 
00639 GrowableArray<PReg*>* NodeBuilder::pass_arguments(PReg* receiver, int nofArgs) {
00640   // Generate code for argument passing (move all args into the right locations).
00641   // If the arguments are passed on the stack (including the receiver) they should
00642   // be assigned in the order of textual appearance. If the receiver is passed in
00643   // a register that should happen at the end to allow this register to be used
00644   // as long as possible.
00645   int nofFormals = (receiver == NULL) ? nofArgs : nofArgs + 1;
00646   GrowableArray<PReg*>* formals = new GrowableArray<PReg*>(nofFormals);
00647   // setup formal receiver and pass if passed on the stack
00648   SAPReg* formalReceiver;
00649   GrowableArray<BlockPReg*> blocks(5);
00650   if (receiver != NULL) {
00651     materialize(receiver, &blocks);
00652     formalReceiver = new SAPReg(_scope, receiverLoc, false, false, bci(), bci());
00653     formals->append(formalReceiver);
00654     if (receiverLoc.isStackLocation()) {
00655       // receiver is passed on stack, must happen before the arguments are passed
00656       append(NodeFactory::new_AssignNode(receiver, formalReceiver));
00657     }
00658   }
00659   // argument range
00660   const int first_arg = exprStack()->length() - nofArgs;
00661   const int limit_arg = exprStack()->length();
00662   int sp;
00663   // materialize blocks
00664   for (sp = first_arg; sp < limit_arg; sp++)  {
00665     PReg* actual = exprStack()->at(sp)->preg();
00666     materialize(actual, &blocks);
00667   }
00668   // pass arguments
00669   for (sp = first_arg; sp < limit_arg; sp++)  {
00670     PReg*   actual = exprStack()->at(sp)->preg();
00671     SAPReg* formal = new SAPReg(_scope, Mapping::outgoingArg(sp - first_arg, nofArgs), false, false, bci(), bci());
00672     formals->append(formal);
00673     append(NodeFactory::new_AssignNode(actual, formal));
00674   }
00675   // pass receiver if not passed already
00676   if ((receiver != NULL) && !receiverLoc.isStackLocation()) {
00677     append(NodeFactory::new_AssignNode(receiver, formalReceiver));
00678   }
00679   return formals;
00680 }
00681 
00682 
00683 void NodeBuilder::gen_normal_send(SendInfo* info, int nofArgs, SAPReg* result) {
00684   GrowableArray<PReg*>* args = pass_arguments(exprStack()->at(exprStack()->length() - nofArgs - 1)->preg(), nofArgs);
00685   SendNode* send = NodeFactory::new_SendNode(info->key, scope()->nlrTestPoint(), args, 
00686                                              copyCurrentExprStack(), false, info);
00687   append(send);
00688   append(NodeFactory::new_AssignNode(send->dest(), result));
00689 }
00690 
00691 
00692 void NodeBuilder::gen_self_send(SendInfo* info, int nofArgs, SAPReg* result) {
00693   GrowableArray<PReg*>* args = pass_arguments(_scope->self()->preg(), nofArgs);
00694   SendNode* send = NodeFactory::new_SendNode(info->key, scope()->nlrTestPoint(), args, 
00695                                              copyCurrentExprStack(), false, info);
00696   append(send);
00697   append(NodeFactory::new_AssignNode(send->dest(), result));
00698 }
00699 
00700 
00701 void NodeBuilder::gen_super_send(SendInfo* info, int nofArgs, SAPReg* result) {
00702   GrowableArray<PReg*>* args = pass_arguments(_scope->self()->preg(), nofArgs);
00703   SendNode* send = NodeFactory::new_SendNode(info->key, scope()->nlrTestPoint(), args, 
00704                                              copyCurrentExprStack(), true, info);
00705   append(send);
00706   append(NodeFactory::new_AssignNode(send->dest(), result));
00707 }
00708 
00709 
00710 void NodeBuilder::normal_send(InterpretedIC* ic) {
00711   int nofArgs = ic->selector()->number_of_arguments();
00712   LookupKey* key = LookupKey::allocate(NULL, ic->selector());
00713   Expr* rcvr = exprStack()->at(exprStack()->length() - nofArgs - 1);
00714   SendInfo* info = new SendInfo(_scope, key, rcvr);
00715   Expr* result = _inliner->inlineNormalSend(info);
00716   exprStack()->pop(nofArgs + 1); // pop arguments & receiver
00717   exprStack()->push(result, _scope, scope()->bci());
00718   abortIfDead(result);
00719 }
00720 
00721 
00722 void NodeBuilder::self_send(InterpretedIC* ic) {
00723   int nofArgs = ic->selector()->number_of_arguments();
00724   LookupKey* key = LookupKey::allocate(_scope->selfKlass(), ic->selector());
00725   SendInfo* info = new SendInfo(_scope, key, _scope->self());
00726   Expr* result = _inliner->inlineSelfSend(info);
00727   exprStack()->pop(nofArgs);    // receiver has not been pushed
00728   exprStack()->push(result, _scope, scope()->bci());
00729   abortIfDead(result);
00730 }
00731 
00732 
00733 void NodeBuilder::super_send(InterpretedIC* ic) {
00734   int nofArgs = ic->selector()->number_of_arguments();
00735   //LookupKey* key = ic->lookupKey(0);
00736   klassOop klass = _scope->selfKlass()->klass_part()->superKlass();
00737   LookupKey* key = LookupKey::allocate(klass, lookupCache::method_lookup(klass, ic->selector()));
00738   SendInfo* info = new SendInfo(_scope, key, _scope->self());
00739   Expr* result = _inliner->inlineSuperSend(info);
00740   exprStack()->pop(nofArgs);    // receiver has not been pushed
00741   exprStack()->push(result, _scope, scope()->bci());
00742   abortIfDead(result);
00743 }
00744 
00745 
00746 void NodeBuilder::double_equal() {
00747   PrimInliner* p = new PrimInliner(this, primitives::equal(), NULL);
00748   p->generate();
00749 }
00750 
00751 
00752 void NodeBuilder::double_not_equal() {
00753   PrimInliner* p = new PrimInliner(this, primitives::not_equal(), NULL);
00754   p->generate();
00755 }
00756 
00757 
00758 void NodeBuilder::method_return(int nofArgs) {
00759   // assign result & return
00760   Expr* result = exprStack()->pop();
00761   if (_current == EndOfCode) {
00762     // scope ends with dead code, i.e., there's no method return
00763     // (e.g., because there is a preceding NLR)
00764     _scope->addResult(new NoResultExpr);
00765     return;
00766   }
00767 
00768   if (result->isNoResultExpr()) {
00769     // scope will never return normally (i.e., is always left via a NLR)
00770     _scope->addResult(result);  // make sure scope->result != NULL
00771   } else {
00772     // return TOS
00773     PReg* src = result->preg();
00774     materialize(src, NULL);
00775     if (_scope->isTop()) {
00776       // real return from nmethod
00777       append(NodeFactory::new_AssignNode(src, _scope->resultPR));
00778       _scope->addResult(result->shallowCopy(_scope->resultPR, _current));
00779     } else {
00780       // inlined return
00781       if (UseNewBackend) {
00782         // The new backend doesn't support InlinedReturnNodes anymore but has
00783         // an explizit ContextZapNode that is used together with an AssignNode.
00784         //
00785         // Note: We don't know if context zapping is really needed before
00786         // the block optimizations, therefore we introduce it eagerly if
00787         // the scope seems to need it. However, the backend will check
00788         // again if it is still necessary (the optimizations can only
00789         // remove the need, not create it).
00790 
00791         // Turned off for now - problem with ScopeDesc - FIX THIS
00792         // if (_scope->needsContextZapping()) append(NodeFactory::new_ContextZapNode(_scope->context()));
00793         append(NodeFactory::new_AssignNode(src, _scope->resultPR));
00794       } else {
00795         if (_scope->needsContextZapping()) {
00796           // keep inlined return node (no context zap node yet)
00797           append(NodeFactory::new_InlinedReturnNode(bci(), src, _scope->resultPR));
00798         } else {
00799           // only assignment required
00800           append(NodeFactory::new_AssignNode(src, _scope->resultPR));
00801         }
00802       }
00803       _scope->addResult(result->shallowCopy(_scope->resultPR, _current));
00804     }
00805   }
00806 
00807   append(scope()->returnPoint());       // connect to return code
00808   // The byte code compiler might generate a pushNil to adjust the stack;
00809   // make sure that code is discarded.
00810   _current = EndOfCode;
00811 }
00812 
00813 
00814 void NodeBuilder::nonlocal_return(int nofArgs) {
00815   // assign result & return
00816   Expr* resultExpr = exprStack()->pop();
00817   PReg* src = resultExpr->preg();
00818   materialize(src, NULL);
00819   if (scope()->isTop()) {
00820     // real NLR from nmethod
00821     append(NodeFactory::new_AssignNode(src, scope()->resultPR));
00822     append(scope()->nlrPoint());
00823   } else {
00824     // NLR from inlined scope
00825     Scope* home = scope()->home();
00826     if (home->isInlinedScope()) {
00827       // the NLR target is in the same nmethod
00828       InlinedScope* h = (InlinedScope*)home;
00829       append(NodeFactory::new_AssignNode(src, h->resultPR));
00830       h->addResult(resultExpr->shallowCopy(h->resultPR, _current));
00831       // jump to home method's return point
00832       // BUG: should zap contexts along the way -- fix this
00833       append(h->returnPoint());
00834     } else {
00835       // NLR target is in a different nmethod -- unwind all sender frames and
00836       // perform a real NLR
00837       // BUG: should zap contexts along the way -- fix this
00838 
00839       // now assign to result register and jump to NLR setup code to set up remaining NLR regs
00840       // NB: each scope needs its own setup node because the home fp/id is different
00841       int endBCI = scope()->nlrPoint()->bci();
00842       bool haveSetupNode = scope()->nlrPoint()->next() != NULL;
00843       assert(!haveSetupNode || scope()->nlrPoint()->next()->isNLRSetupNode(), "expected setup node");
00844       PReg* res = haveSetupNode ? ((NonTrivialNode*)scope()->nlrPoint()->next())->src() : 
00845                                   new SAPReg(scope(), NLRResultLoc, true, true, bci(), endBCI);
00846       append(NodeFactory::new_AssignNode(src, res));
00847       append(scope()->nlrPoint());
00848       if (!haveSetupNode) {
00849         // lazily create setup code
00850         append_exit(NodeFactory::new_NLRSetupNode(res, endBCI));
00851       }
00852     }
00853   }
00854   // (the byte code compiler might generate a pushNil to adjust the stack)
00855   _current = EndOfCode;
00856 }
00857 
00858 GrowableArray<NonTrivialNode*>* NodeBuilder::nodesBetween(Node* from, Node* to) {
00859   // collect assignments along the path from --> to (for splitting)
00860   GrowableArray<NonTrivialNode*>* nodes = new GrowableArray<NonTrivialNode*>(5);
00861   Node* n = from;
00862   while (n != to) {
00863     if (!n->hasSingleSuccessor()) return NULL;   // can't copy both paths
00864     bool shouldCopy = n->shouldCopyWhenSplitting();
00865     bool ok = (n == from) ||
00866                shouldCopy ||
00867                n->isTrivial() ||
00868                n->isMergeNode();
00869     if (!ok) return NULL;                             // can't copy this node
00870     if (shouldCopy && n != from) nodes->append((NonTrivialNode*)n);
00871     n = n->next();
00872   }
00873   return nodes;
00874 }
00875 
00876 MergeNode* NodeBuilder::insertMergeBefore(Node* n) {
00877   // insert a MergeNode before n
00878   assert(n->hasSinglePredecessor(), "should have only one predecessor");
00879   MergeNode* merge = NodeFactory::new_MergeNode(n->bci());
00880   Node* prev = n->firstPrev();
00881   prev->moveNext(n, merge);
00882   merge->setPrev(prev);
00883   n->removePrev(prev);
00884   merge->append(n);
00885   return merge;
00886 }
00887 
00888 
00889 static int split_count = 0; // for conditional breakpoints (debugging)
00890 
00891 void NodeBuilder::splitMergeExpr(Expr* expr, TypeTestNode* test) {
00892   // Split MergeExpressions (currently works only for booleans).
00893   // expr is the expression (generated somewhere upstream), test is the (only) node
00894   // testing this expression.  If there's nothing "complicated" inbetween, split the
00895   // merge to avoid the type test.
00896   split_count++;
00897   GrowableArray<Expr*>* exprsToSplit = splittablePaths(expr, test);
00898   if (!exprsToSplit) return;
00899  
00900   for (int i = exprsToSplit->length() - 1; i >= 0; i--) {
00901     Expr* e = exprsToSplit->at(i);
00902     Node* start = e->node();
00903     GrowableArray<NonTrivialNode*>* nodesToCopy = nodesBetween(start, test);
00904     assert(nodesToCopy != NULL, "should have worked");
00905 
00906     // find corresponding 'to' node in type test
00907     klassOop c = e->asConstantExpr()->klass();
00908     int j = test->classes()->length();
00909     while (j-- > 0 && test->classes()->at(j) != c) ;
00910     assert(j >= 0, "didn't find klass in type test");
00911     Node* to = test->next(j+1); // +1 because next(i) is branch for class i-1
00912     if (CompilerDebug) cout(PrintSplitting)->print("%*s*splitting merge expr: from N%d to N%d (%dth split)\n", _scope->depth*2, "", start->id(), to->id(), split_count);
00913     if (!to->isMergeNode()) {
00914       to = insertMergeBefore(to);       // insert a MergeNode inbetween
00915     }
00916 
00917     // disconnect defining node from its current successor
00918     start->removeNext(start->next());
00919     // append copies of all assignments
00920     Node* current = start;
00921 #ifdef ASSERT
00922     bool found = nodesToCopy->length() == 0;    // hard to test if no nodes to copy, so assume it's ok
00923 #endif
00924     for (int i = 0; i < nodesToCopy->length(); i++) {
00925       NonTrivialNode* orig = nodesToCopy->at(i);
00926       Node* copy = orig->copy(NULL, NULL);
00927       if (CompilerDebug) cout(PrintSplitting)->print("%*s*  (copying node N%d along the path -> N%d)\n", _scope->depth*2, "", orig->id(), copy->id());
00928       current = current->append(copy);
00929 #ifdef ASSERT
00930       if (orig->dest() == test->src()) found = true;
00931 #endif
00932     }
00933 #ifdef ASSERT
00934     if (!found) {
00935       // no assignment to tested PReg found along path; must be earlier
00936       // check only leftmost path (must be assigned along any path)
00937       for (Node* n = start; n && !found; n = n->firstPrev()) {
00938         if (n->hasDest() && ((NonTrivialNode*)n)->dest() == test->src()) {
00939           found = true;
00940         }
00941       }
00942       assert(found, "assignment to tested PReg not found");
00943    }
00944 #endif
00945     // connect to 'to' node
00946     current->append(to);
00947   }
00948 }
00949 
00950 GrowableArray<Expr*>* NodeBuilder::splittablePaths(const Expr* expr, const TypeTestNode* test) const {
00951   // test if expr can be split
00952   if (!Splitting) return NULL;
00953   if (!expr->isMergeExpr()) return NULL;
00954   MergeExpr* m = expr->asMergeExpr();
00955   if (!m->isSplittable()) return NULL;
00956 
00957   GrowableArray<Node*>* exprNodes = new GrowableArray<Node*>(10); // start nodes of all paths
00958   GrowableArray<Expr*>* okExprs   = new GrowableArray<Expr*>(10);  // those who are splittable
00959 
00960   // collect all paths that look splittable
00961   for (int i = m->exprs->length() - 1; i >= 0; i--) {
00962     for (Expr* x = m->exprs->at(i); x; x = x->next) {
00963       Node* start = x->node();
00964       exprNodes->append(start);
00965       if (!x->isConstantExpr()) continue;
00966       // check if there is a 'simple' path between defining node and type test node -> split if possible
00967       const Node* n = start;
00968       while (n != test) {
00969         if (!n->hasSingleSuccessor()) goto nextExpr;   // can't copy both paths
00970         bool ok = (n == start) ||
00971                    n->isTrivial() ||
00972                    n->isAssignNode() ||
00973                    n->isMergeNode();
00974         if (!ok) goto nextExpr;                       // can't copy this node
00975         n = n->next();
00976       }
00977       // ok, the path from this node is splittable
00978       okExprs->append(x);
00979     }
00980 nextExpr: ;
00981   }
00982 
00983   // check that no exprNode is along the path from any other exprNode to the test node
00984   // this should be #ifdef ASSERT but for now always check to make sure there are no lurking bugs  -Urs 4/27/96
00985   for (i = okExprs->length() - 1; i >= 0; i--) {
00986     Node* start = okExprs->at(i)->node()->next();
00987     for (Node* n = start; n != (Node*)test; n = n->next()) {
00988       if (exprNodes->contains(n)) {
00989         lprintf("error in splittable boolean expression:\n");
00990         m->print();
00991         okExprs->at(i)->print();
00992 #ifdef DEBUG
00993         printNodes(okExprs->at(i)->node());
00994 #endif
00995         for (int j = 0; j < exprNodes->length(); j++) { 
00996           exprNodes->at(j)->print();
00997           lprintf("\n");
00998         }
00999         fatal("compiler error");
01000       }
01001     }
01002   }
01003 
01004   return okExprs;
01005 }
01006 
01007 void NodeBuilder::allocate_closure(AllocationType type, int nofArgs, methodOop method) {
01008   PReg* context;
01009   if (type == tos_as_scope) {
01010     context = exprStack()->pop()->preg();
01011   } else {
01012     context = _scope->context();
01013   }
01014   CompileTimeClosure* closure = new CompileTimeClosure(_scope, method, context, nofArgs);
01015   BlockPReg* block = new BlockPReg(_scope, closure, bci(), EpilogueBCI);
01016   append(NodeFactory::new_BlockCreateNode(block, copyCurrentExprStack()));
01017   exprStack()->push(new BlockExpr(block, _current), _scope, scope()->bci());
01018 }
01019 
01020 
01021 static methodOopDesc::Block_Info incoming_info(methodOop m) {
01022   // this function is here for compatibility reasons only
01023   // should go away at some point: block_info replaced
01024   // incoming_info, but is only defined for blocks
01025   if (m->is_blockMethod()) {
01026     return m->block_info();
01027   } else {
01028     return methodOopDesc::expects_self;
01029   }
01030 }
01031 
01032 
01033 void NodeBuilder::allocate_context(int nofTemps, bool forMethod) {
01034   _scope->createContextTemporaries(nofTemps);
01035   assert(!scope()->contextInitializer(), "should not already have a contextInitializer");
01036   PReg* parent; // previous context in the context chain
01037   if (forMethod) {
01038     // method, not block context points to current stack frame
01039     parent = new SAPReg(_scope, frameLoc, true, true, PrologueBCI, EpilogueBCI);
01040   } else {
01041     // context points to previous (incoming) context, if there
01042     assert(incoming_info(_scope->method()) != methodOopDesc::expects_self, "fix this");
01043     assert(incoming_info(_scope->method()) != methodOopDesc::expects_parameter, "fix this");
01044     if (_scope->isTop()) {
01045       parent =
01046         (incoming_info(_scope->method()) == methodOopDesc::expects_context)
01047         ? _scope->self()->preg()                // incoming context is passed in self's location (interpreter invariant); fix this to use different PReg
01048         : NULL;                                 // parent should never be used, set to 0 for debugging
01049                                                 // (note: the interpreter sets parent always to self)
01050     } else {
01051       // create new context PReg (_scope->context() is the context passed in by the caller)
01052       parent = _scope->context();
01053       _scope->setContext(new SAPReg(_scope, PrologueBCI, EpilogueBCI));
01054     }
01055   }
01056   ContextCreateNode* creator = NodeFactory::new_ContextCreateNode(parent, _scope->context(), nofTemps, copyCurrentExprStack());
01057   append(creator);
01058   // append context initializer and initialize with nil
01059   scope()->set_contextInitializer(NodeFactory::new_ContextInitNode(creator));
01060   append(scope()->contextInitializer());
01061   ConstantExpr* nil = new ConstantExpr(nilObj, new_ConstPReg(_scope, nilObj), NULL);
01062   for (int i = 0; i < nofTemps; i++) scope()->contextInitializer()->initialize(i, nil);
01063 }
01064 
01065 
01066 void NodeBuilder::removeContextCreation() {
01067   assert(scope()->contextInitializer() != NULL, "must have context");
01068   ContextCreateNode* creator = scope()->contextInitializer()->creator();
01069   creator->eliminate(creator->bb(), NULL, true, false);         // delete creator node
01070   scope()->contextInitializer()->notifyNoContext();             // let initializer know about it
01071 }
01072 
01073 
01074 void NodeBuilder::set_self_via_context() {
01075   if (Inline) {
01076     Scope* s = _scope->parent();
01077     if (s->isInlinedScope()) {
01078       // self doesn't need to be set -- can directly use the Expr of the enclosing scope
01079       assert(_scope->self() == ((InlinedScope*)s)->self(), "should have identical selves");
01080       return;
01081     }
01082   }
01083 
01084   // prevent multiple initializations (see BlockScope::initializeSelf)
01085   if (_scope->is_self_initialized()) return;
01086   _scope->set_self_initialized();
01087 
01088   // must load self at runtime; first compute home context no
01089   int contextNo = _scope->homeContext();
01090   if (_scope->allocatesInterpretedContext()) {
01091     // correct contextNo: the set_self_via_context works on the incoming context
01092     // -> subtract 1 (homeContext() already counts the context allocated in this
01093     // method (if there is one)
01094     assert(_scope->contextInitializer() != NULL, "should have a _contextInitializer already");
01095     contextNo--;
01096   }
01097 
01098   // do uplevel access and store into self
01099   // Note: this should use the same mechanism as access_temporary(...). However,
01100   // access_temporary relies on the fact that a possible local context is already
01101   // allocated. Thus, for the time being, explicitly generate
01102   // the uplevel access node. Note: the incoming context is in the recv location!
01103   const int self_no     = 0; // self is always the first entry in the top context, if there
01104   PReg* reg = _scope->self()->preg();
01105   append(NodeFactory::new_LoadUplevelNode(reg, reg, contextNo, contextOopDesc::temp0_word_offset() + self_no, NULL));
01106 }
01107 
01108 
01109 Expr* NodeBuilder::copy_into_context(Expr* e, int no) {
01110   if (e->isBlockExpr()) {
01111     // A block must be stored into a context (e.g. it's passed in as an arg and the arg
01112     // is uplevel-accessed).
01113     // Must materialize it here to make sure it's created; this BlockMaterializeNode should
01114     // be deleted if the context is eliminated, so register it with the context.
01115     BlockPReg* block = (BlockPReg*)e->preg();
01116     BlockMaterializeNode* n = NodeFactory::new_BlockMaterializeNode(block, copyCurrentExprStack());
01117     scope()->contextInitializer()->addBlockMaterializer(n);
01118     append(n);
01119     // Remember the context location so we can later retrieve the corresponding context.
01120     // (We're just using a Location as a convenient way to denote a particular location;
01121     // this doesn't have anything to do with register / context allocation per se, so don't
01122     // use the location for anything else.)
01123     Location* loc = Mapping::new_contextTemporary(no, no, scope()->scopeID());
01124     block->addContextCopy(loc);
01125     // don't copy the block so it can still be inlined (handled specially in context initializer if
01126     // context is created)
01127     return e;
01128   } else {
01129     return e->shallowCopy(new SAPReg(scope(), PrologueBCI, EpilogueBCI, true), NULL);
01130   }
01131 }
01132 
01133 
01134 void NodeBuilder::copy_self_into_context() {
01135   const int self_no = 0; // self is always the first temporary in a context, if there
01136   // caution: must create new expr/preg for self in context because the two locations must be different 
01137   Expr* self_expr_in_context = copy_into_context(scope()->self(), self_no);
01138   scope()->contextTemporariesAtPut(self_no, self_expr_in_context);
01139   scope()->contextInitializer()->initialize(self_no, scope()->self());
01140 }
01141 
01142 
01143 void NodeBuilder::copy_argument_into_context(int argNo, int no) {
01144   // caution: must create new expr/preg for arg in context because the two locations must be different 
01145   // i.e., arg is on stack, arg in context may be on heap
01146   Expr* arg_expr_in_context = copy_into_context(scope()->argument(argNo), no);
01147   scope()->contextTemporariesAtPut(no, arg_expr_in_context);
01148   scope()->contextInitializer()->initialize(no, scope()->argument(argNo));
01149 }
01150 
01151 
01152 void NodeBuilder::zap_scope() {
01153   assert(scope()->isMethodScope(), "blocks cannot be target of a NLR, no zap required");
01154   assert(scope()->contextInitializer() != NULL, "should have a context allocated");
01155   // no explicit node generated
01156 }
01157 
01158 
01159 void NodeBuilder::predict_prim_call(primitive_desc* pdesc, int failure_start) {
01160   // ignored
01161 }
01162 
01163 
01164 PReg* NodeBuilder::float_at(int fno) {
01165   if (UseFPUStack) {
01166     if (fno < scope()->nofFloatTemporaries()) {
01167       // fno refers to a float temporary
01168       return scope()->floatTemporary(fno)->preg();
01169     } else {
01170       // fno refers to a float on the float expression stack,
01171       // it must refer to the top since code is generated for
01172       // a stack machine
01173       return new SAPReg(_scope, topOfFloatStack, true, true, bci(), bci());
01174     }
01175   } else {
01176     // intermediate expressions are treated as temporaries
01177     return scope()->floatTemporary(fno)->preg();
01178   }
01179 }
01180 
01181 
01182 void NodeBuilder::float_allocate(int nofFloatTemps, int nofFloatExprs) {
01183   // nofFloats 64bit floats are allocated and initialized to NaN
01184   // in the following set of operations float(fno) (fno = float no.)
01185   // refers to one of these floats within the range [0..nofFloats[.
01186   //
01187   // Example code for a method containing the following code
01188   // (strictly using the stack-machine paradigm)
01189   //
01190   // | a <!Float>                       ; mapped to 0
01191   //   b <!Float>                       ; mapped to 1
01192   //   c <!Float>                       ; mapped to 2
01193   // |
01194   //
01195   // a := 3.0.
01196   // b := 4.0.
01197   // c := a + b.
01198   // ^ c
01199   //
01200   // float_allocate     5               ; two more for expression stack temporaries (mapped to 3 & 4)
01201   // float_set          3, 3.0          ; a := 3.0
01202   // float_move         0, 3
01203   // float_set          3, 4.0          ; b := 4.0
01204   // float_move         1, 3
01205   // float_move         3, 0            ; push a
01206   // float_move         4, 1            ; push b
01207   // float_binaryOp     3, add          ; add
01208   // float_move         2, 3            ; store to c
01209   // float_move         3, 2            ; push c
01210   // float_unaryOpToOop 3, oopify       ; push c converted to oop
01211   // return_tos                         ; return tos
01212   int size = nofFloatTemps + nofFloatExprs;
01213   assert(size == method()->total_number_of_floats(), "inconsistency");
01214   // floatTemporaries are allocated in InlinedScope::genCode()
01215 }
01216 
01217 
01218 void NodeBuilder::float_floatify(Floats::Function f, int fno) {
01219   // top of stack must be a boxed float, it is unboxed and stored at float(fno).
01220   Expr* t = _exprStack->pop();
01221   if (t->hasKlass() && t->klass() == doubleKlassObj) {
01222     // no type test needed
01223   } else {
01224     // put in a type test - fix this!
01225   }
01226   append(NodeFactory::new_FloatUnaryArithNode(float_at(fno), t->preg(), f2FloatArithOp));
01227 }
01228 
01229 
01230 void NodeBuilder::float_move(int to, int from) {
01231   // float(to) := float(from)
01232   append(NodeFactory::new_AssignNode(float_at(from), float_at(to)));
01233 }
01234 
01235 
01236 void NodeBuilder::float_set(int to, doubleOop value) {
01237   // float(to) := value
01238   ConstPReg* val = new_ConstPReg(_scope, value);
01239   append(NodeFactory::new_AssignNode(val, float_at(to)));
01240 }
01241 
01242 
01243 void NodeBuilder::float_nullary(Floats::Function f, int to) {
01244   // float(to) := f()
01245   // f refers to one of the functions in Floats
01246   switch (f) {
01247     case Floats::zero   : float_set(to, oopFactory::new_double(0.0)); break;
01248     case Floats::one    : float_set(to, oopFactory::new_double(1.0)); break;
01249     default             : fatal1("bad float nullary code %d", f);
01250   }
01251 }
01252 
01253 
01254 void NodeBuilder::float_unary(Floats::Function f, int fno) {
01255   // float(fno) := f(float(fno))
01256   // f refers to one of the functions in Floats
01257   ArithOpCode op;
01258   switch (f) {
01259     case Floats::abs    : op = fAbsArithOp; break;
01260     case Floats::negated: op = fNegArithOp; break;
01261     case Floats::squared: op = fSqrArithOp; break;
01262     case Floats::sqrt   : Unimplemented();
01263     case Floats::sin    : Unimplemented();
01264     case Floats::cos    : Unimplemented();
01265     case Floats::tan    : Unimplemented();
01266     case Floats::exp    : Unimplemented();
01267     case Floats::ln     : Unimplemented();
01268     default             : fatal1("bad float unary code %d", f);
01269   }
01270   PReg* preg = float_at(fno);
01271   append(NodeFactory::new_FloatUnaryArithNode(preg, preg, op));
01272 }
01273 
01274 
01275 void NodeBuilder::float_binary(Floats::Function f, int fno) {
01276   // float(fno) := f(float(fno), float(fno+1))
01277   // f refers to one of the functions in Floats
01278   ArithOpCode op;
01279   switch (f) {
01280     case Floats::add     : op = fAddArithOp; break;
01281     case Floats::subtract: op = fSubArithOp; break;
01282     case Floats::multiply: op = fMulArithOp; break;
01283     case Floats::divide  : op = fDivArithOp; break;
01284     case Floats::modulo  : op = fModArithOp; break;
01285     default              : fatal1("bad float binary code %d", f);
01286   }
01287   PReg* op1 = float_at(fno);
01288   PReg* op2 = float_at(fno+1);
01289   append(NodeFactory::new_FloatArithRRNode(op1, op1, op, op2));
01290 }
01291 
01292 
01293 void NodeBuilder::float_unaryToOop(Floats::Function f, int fno) {
01294   // push f(float(fno)) on top of (oop) expression stack, result is an oop
01295   // f refers to one of the functions in Floats
01296   PReg* src = float_at(fno);
01297   SAPReg* res = new SAPReg(_scope);
01298   switch (f) {
01299     case Floats::is_zero: // fall through
01300     case Floats::is_not_zero:  
01301       { ConstPReg* zero = new_ConstPReg(_scope, oopFactory::new_double(0.0));
01302         NodeFactory::new_FloatArithRRNode(new NoPReg(_scope), src, fCmpArithOp, zero);
01303         BranchOpCode cond = f == Floats::is_zero ? EQBranchOp : NEBranchOp;
01304         _exprStack->push(PrimInliner::generate_cond(cond, this, res), scope(), scope()->bci());
01305       }
01306       break;
01307     case Floats::oopify: 
01308       { append(NodeFactory::new_FloatUnaryArithNode(res, src, f2OopArithOp));
01309         Expr* result = new KlassExpr(doubleKlassObj, res, current());
01310         _exprStack->push(result, scope(), scope()->bci());
01311       }
01312       break;
01313     default: fatal1("bad float unaryToOop code %d", f);
01314   }
01315 }
01316 
01317 
01318 void NodeBuilder::float_binaryToOop(Floats::Function f, int fno) {
01319   // push f(float(fno), float(fno+1)) on top of (oop) expression stack, result is an oop
01320   // f refers to one of the functions in Floats
01321   Assembler::Condition cc1;
01322   switch (f) {
01323     case Floats::is_equal        : cc1 = Assembler::equal;              break;
01324     case Floats::is_not_equal    : cc1 = Assembler::notEqual;           break;
01325     case Floats::is_less         : cc1 = Assembler::less;               break;
01326     case Floats::is_less_equal   : cc1 = Assembler::lessEqual;          break;
01327     case Floats::is_greater      : cc1 = Assembler::greater;            break;
01328     case Floats::is_greater_equal: cc1 = Assembler::greaterEqual;       break;
01329     default                      : fatal1("bad float comparison code %d", f);
01330   }
01331   int mask;
01332   Assembler::Condition cond;
01333   MacroAssembler::fpu_mask_and_cond_for(cc1, mask, cond);
01334   PReg* op1 = float_at(fno);
01335   PReg* op2 = float_at(fno+1);
01336   SAPReg* fpu_status = new SAPReg(_scope, Mapping::asLocation(eax), false, false, bci(), bci());
01337   append(NodeFactory::new_FloatArithRRNode(fpu_status, op1, fCmpArithOp, op2));
01338   append(NodeFactory::new_ArithRCNode(new NoPReg(_scope), fpu_status, TestArithOp, mask));
01339   BranchOpCode cc2;
01340   switch (cond) {
01341     case Assembler::zero   : cc2 = EQBranchOp; break;
01342     case Assembler::notZero: cc2 = NEBranchOp; break;
01343     default                : ShouldNotReachHere();
01344   }
01345   SAPReg* res = new SAPReg(_scope);
01346   _exprStack->push(PrimInliner::generate_cond(cc2, this, res), scope(), scope()->bci());
01347 }
01348 
01349 
01350 # endif

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