LCOV - code coverage report
Current view: directory - js/src/frontend - FoldConstants.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 470 336 71.5 %
Date: 2012-06-02 Functions: 6 6 100.0 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=8 sw=4 et tw=99:
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is Mozilla Communicator client code, released
      18                 :  * March 31, 1998.
      19                 :  *
      20                 :  * The Initial Developer of the Original Code is
      21                 :  * Netscape Communications Corporation.
      22                 :  * Portions created by the Initial Developer are Copyright (C) 1998-2011
      23                 :  * the Initial Developer. All Rights Reserved.
      24                 :  *
      25                 :  * Contributor(s):
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      29                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #include "frontend/FoldConstants.h"
      42                 : 
      43                 : #include "jslibmath.h"
      44                 : 
      45                 : #include "frontend/BytecodeEmitter.h"
      46                 : #include "frontend/ParseNode.h"
      47                 : 
      48                 : #if JS_HAS_XML_SUPPORT
      49                 : #include "jsxml.h"
      50                 : #endif
      51                 : 
      52                 : #include "jsatominlines.h"
      53                 : 
      54                 : #include "vm/String-inl.h"
      55                 : 
      56                 : using namespace js;
      57                 : 
      58                 : static ParseNode *
      59        22901455 : ContainsVarOrConst(ParseNode *pn)
      60                 : {
      61        22901455 :     if (!pn)
      62         3524594 :         return NULL;
      63        19376861 :     if (pn->isKind(PNK_VAR) || pn->isKind(PNK_CONST))
      64           30881 :         return pn;
      65        19345980 :     switch (pn->getArity()) {
      66                 :       case PN_LIST:
      67         9223379 :         for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
      68         6940920 :             if (ParseNode *pnt = ContainsVarOrConst(pn2))
      69           35806 :                 return pnt;
      70                 :         }
      71         2282459 :         break;
      72                 :       case PN_TERNARY:
      73          316873 :         if (ParseNode *pnt = ContainsVarOrConst(pn->pn_kid1))
      74            2039 :             return pnt;
      75          314834 :         if (ParseNode *pnt = ContainsVarOrConst(pn->pn_kid2))
      76            2592 :             return pnt;
      77          312242 :         return ContainsVarOrConst(pn->pn_kid3);
      78                 :       case PN_BINARY:
      79                 :         /*
      80                 :          * Limit recursion if pn is a binary expression, which can't contain a
      81                 :          * var statement.
      82                 :          */
      83         4369816 :         if (!pn->isOp(JSOP_NOP))
      84         2077424 :             return NULL;
      85         2292392 :         if (ParseNode *pnt = ContainsVarOrConst(pn->pn_left))
      86             857 :             return pnt;
      87         2291535 :         return ContainsVarOrConst(pn->pn_right);
      88                 :       case PN_UNARY:
      89         4587638 :         if (!pn->isOp(JSOP_NOP))
      90          702791 :             return NULL;
      91         3884847 :         return ContainsVarOrConst(pn->pn_kid);
      92                 :       case PN_NAME:
      93         4677222 :         return ContainsVarOrConst(pn->maybeExpr());
      94                 :       case PN_NAMESET:
      95               0 :         return ContainsVarOrConst(pn->pn_tree);
      96                 :       default:;
      97                 :     }
      98         5358625 :     return NULL;
      99                 : }
     100                 : 
     101                 : /*
     102                 :  * Fold from one constant type to another.
     103                 :  * XXX handles only strings and numbers for now
     104                 :  */
     105                 : static JSBool
     106          605469 : FoldType(JSContext *cx, ParseNode *pn, ParseNodeKind kind)
     107                 : {
     108          605469 :     if (!pn->isKind(kind)) {
     109          432380 :         switch (kind) {
     110                 :           case PNK_NUMBER:
     111          268743 :             if (pn->isKind(PNK_STRING)) {
     112                 :                 double d;
     113             280 :                 if (!ToNumber(cx, StringValue(pn->pn_atom), &d))
     114               0 :                     return JS_FALSE;
     115             280 :                 pn->pn_dval = d;
     116             280 :                 pn->setKind(PNK_NUMBER);
     117             280 :                 pn->setOp(JSOP_DOUBLE);
     118                 :             }
     119          268743 :             break;
     120                 : 
     121                 :           case PNK_STRING:
     122          163637 :             if (pn->isKind(PNK_NUMBER)) {
     123              19 :                 JSString *str = js_NumberToString(cx, pn->pn_dval);
     124              19 :                 if (!str)
     125               0 :                     return JS_FALSE;
     126              19 :                 pn->pn_atom = js_AtomizeString(cx, str);
     127              19 :                 if (!pn->pn_atom)
     128               0 :                     return JS_FALSE;
     129              19 :                 pn->setKind(PNK_STRING);
     130              19 :                 pn->setOp(JSOP_STRING);
     131                 :             }
     132          163637 :             break;
     133                 : 
     134                 :           default:;
     135                 :         }
     136                 :     }
     137          605469 :     return JS_TRUE;
     138                 : }
     139                 : 
     140                 : /*
     141                 :  * Fold two numeric constants.  Beware that pn1 and pn2 are recycled, unless
     142                 :  * one of them aliases pn, so you can't safely fetch pn2->pn_next, e.g., after
     143                 :  * a successful call to this function.
     144                 :  */
     145                 : static JSBool
     146            1324 : FoldBinaryNumeric(JSContext *cx, JSOp op, ParseNode *pn1, ParseNode *pn2,
     147                 :                   ParseNode *pn, TreeContext *tc)
     148                 : {
     149                 :     double d, d2;
     150                 :     int32_t i, j;
     151                 : 
     152            1324 :     JS_ASSERT(pn1->isKind(PNK_NUMBER) && pn2->isKind(PNK_NUMBER));
     153            1324 :     d = pn1->pn_dval;
     154            1324 :     d2 = pn2->pn_dval;
     155            1324 :     switch (op) {
     156                 :       case JSOP_LSH:
     157                 :       case JSOP_RSH:
     158             100 :         i = js_DoubleToECMAInt32(d);
     159             100 :         j = js_DoubleToECMAInt32(d2);
     160             100 :         j &= 31;
     161             100 :         d = (op == JSOP_LSH) ? i << j : i >> j;
     162             100 :         break;
     163                 : 
     164                 :       case JSOP_URSH:
     165               0 :         j = js_DoubleToECMAInt32(d2);
     166               0 :         j &= 31;
     167               0 :         d = js_DoubleToECMAUint32(d) >> j;
     168               0 :         break;
     169                 : 
     170                 :       case JSOP_ADD:
     171              82 :         d += d2;
     172              82 :         break;
     173                 : 
     174                 :       case JSOP_SUB:
     175             165 :         d -= d2;
     176             165 :         break;
     177                 : 
     178                 :       case JSOP_MUL:
     179             687 :         d *= d2;
     180             687 :         break;
     181                 : 
     182                 :       case JSOP_DIV:
     183             290 :         if (d2 == 0) {
     184                 : #if defined(XP_WIN)
     185                 :             /* XXX MSVC miscompiles such that (NaN == 0) */
     186                 :             if (JSDOUBLE_IS_NaN(d2))
     187                 :                 d = js_NaN;
     188                 :             else
     189                 : #endif
     190             254 :             if (d == 0 || JSDOUBLE_IS_NaN(d))
     191              56 :                 d = js_NaN;
     192             198 :             else if (JSDOUBLE_IS_NEG(d) != JSDOUBLE_IS_NEG(d2))
     193              48 :                 d = js_NegativeInfinity;
     194                 :             else
     195             150 :                 d = js_PositiveInfinity;
     196                 :         } else {
     197              36 :             d /= d2;
     198                 :         }
     199             290 :         break;
     200                 : 
     201                 :       case JSOP_MOD:
     202               0 :         if (d2 == 0) {
     203               0 :             d = js_NaN;
     204                 :         } else {
     205               0 :             d = js_fmod(d, d2);
     206                 :         }
     207               0 :         break;
     208                 : 
     209                 :       default:;
     210                 :     }
     211                 : 
     212                 :     /* Take care to allow pn1 or pn2 to alias pn. */
     213            1324 :     if (pn1 != pn)
     214            1069 :         tc->freeTree(pn1);
     215            1324 :     if (pn2 != pn)
     216            1324 :         tc->freeTree(pn2);
     217            1324 :     pn->setKind(PNK_NUMBER);
     218            1324 :     pn->setOp(JSOP_DOUBLE);
     219            1324 :     pn->setArity(PN_NULLARY);
     220            1324 :     pn->pn_dval = d;
     221            1324 :     return JS_TRUE;
     222                 : }
     223                 : 
     224                 : #if JS_HAS_XML_SUPPORT
     225                 : 
     226                 : static JSBool
     227             576 : FoldXMLConstants(JSContext *cx, ParseNode *pn, TreeContext *tc)
     228                 : {
     229             576 :     JS_ASSERT(pn->isArity(PN_LIST));
     230             576 :     ParseNodeKind kind = pn->getKind();
     231             576 :     ParseNode **pnp = &pn->pn_head;
     232             576 :     ParseNode *pn1 = *pnp;
     233             576 :     JSString *accum = NULL;
     234             576 :     JSString *str = NULL;
     235             576 :     if ((pn->pn_xflags & PNX_CANTFOLD) == 0) {
     236             576 :         if (kind == PNK_XMLETAGO)
     237             111 :             accum = cx->runtime->atomState.etagoAtom;
     238             465 :         else if (kind == PNK_XMLSTAGO || kind == PNK_XMLPTAGC)
     239             336 :             accum = cx->runtime->atomState.stagoAtom;
     240                 :     }
     241                 : 
     242                 :     /*
     243                 :      * GC Rooting here is tricky: for most of the loop, |accum| is safe via
     244                 :      * the newborn string root. However, when |pn2->getKind()| is PNK_XMLCDATA,
     245                 :      * PNK_XMLCOMMENT, or PNK_XMLPI it is knocked out of the newborn root.
     246                 :      * Therefore, we have to add additonal protection from GC nesting under
     247                 :      * js_ConcatStrings.
     248                 :      */
     249                 :     ParseNode *pn2;
     250                 :     uint32_t i, j;
     251            1346 :     for (pn2 = pn1, i = j = 0; pn2; pn2 = pn2->pn_next, i++) {
     252                 :         /* The parser already rejected end-tags with attributes. */
     253             770 :         JS_ASSERT(kind != PNK_XMLETAGO || i == 0);
     254             770 :         switch (pn2->getKind()) {
     255                 :           case PNK_XMLATTR:
     256               9 :             if (!accum)
     257               0 :                 goto cantfold;
     258                 :             /* FALL THROUGH */
     259                 :           case PNK_XMLNAME:
     260                 :           case PNK_XMLSPACE:
     261                 :           case PNK_XMLTEXT:
     262                 :           case PNK_STRING:
     263             770 :             if (pn2->isArity(PN_LIST))
     264               0 :                 goto cantfold;
     265             770 :             str = pn2->pn_atom;
     266             770 :             break;
     267                 : 
     268                 :           case PNK_XMLCDATA:
     269               0 :             str = js_MakeXMLCDATAString(cx, pn2->pn_atom);
     270               0 :             if (!str)
     271               0 :                 return JS_FALSE;
     272               0 :             break;
     273                 : 
     274                 :           case PNK_XMLCOMMENT:
     275               0 :             str = js_MakeXMLCommentString(cx, pn2->pn_atom);
     276               0 :             if (!str)
     277               0 :                 return JS_FALSE;
     278               0 :             break;
     279                 : 
     280                 :           case PNK_XMLPI: {
     281               0 :             XMLProcessingInstruction &pi = pn2->asXMLProcessingInstruction();
     282               0 :             str = js_MakeXMLPIString(cx, pi.target(), pi.data());
     283               0 :             if (!str)
     284               0 :                 return JS_FALSE;
     285               0 :             break;
     286                 :           }
     287                 : 
     288                 :           cantfold:
     289                 :           default:
     290               0 :             JS_ASSERT(*pnp == pn1);
     291               0 :             if ((kind == PNK_XMLSTAGO || kind == PNK_XMLPTAGC) &&
     292                 :                 (i & 1) ^ (j & 1)) {
     293                 : #ifdef DEBUG_brendanXXX
     294                 :                 printf("1: %d, %d => ", i, j);
     295                 :                 if (accum)
     296                 :                     FileEscapedString(stdout, accum, 0);
     297                 :                 else
     298                 :                     fputs("NULL", stdout);
     299                 :                 fputc('\n', stdout);
     300                 : #endif
     301               0 :             } else if (accum && pn1 != pn2) {
     302               0 :                 while (pn1->pn_next != pn2) {
     303               0 :                     pn1 = tc->freeTree(pn1);
     304               0 :                     --pn->pn_count;
     305                 :                 }
     306               0 :                 pn1->setKind(PNK_XMLTEXT);
     307               0 :                 pn1->setOp(JSOP_STRING);
     308               0 :                 pn1->setArity(PN_NULLARY);
     309               0 :                 pn1->pn_atom = js_AtomizeString(cx, accum);
     310               0 :                 if (!pn1->pn_atom)
     311               0 :                     return JS_FALSE;
     312               0 :                 JS_ASSERT(pnp != &pn1->pn_next);
     313               0 :                 *pnp = pn1;
     314                 :             }
     315               0 :             pnp = &pn2->pn_next;
     316               0 :             pn1 = *pnp;
     317               0 :             accum = NULL;
     318               0 :             continue;
     319                 :         }
     320                 : 
     321             770 :         if (accum) {
     322                 :             {
     323                 :                 str = ((kind == PNK_XMLSTAGO || kind == PNK_XMLPTAGC) && i != 0)
     324              18 :                       ? js_AddAttributePart(cx, i & 1, accum, str)
     325             659 :                       : js_ConcatStrings(cx, accum, str);
     326                 :             }
     327             641 :             if (!str)
     328               0 :                 return JS_FALSE;
     329                 : #ifdef DEBUG_brendanXXX
     330                 :             printf("2: %d, %d => ", i, j);
     331                 :             FileEscapedString(stdout, str, 0);
     332                 :             printf(" (%u)\n", str->length());
     333                 : #endif
     334             641 :             ++j;
     335                 :         }
     336             770 :         accum = str;
     337                 :     }
     338                 : 
     339             576 :     if (accum) {
     340             576 :         str = NULL;
     341             576 :         if ((pn->pn_xflags & PNX_CANTFOLD) == 0) {
     342             576 :             if (kind == PNK_XMLPTAGC)
     343             225 :                 str = cx->runtime->atomState.ptagcAtom;
     344             351 :             else if (kind == PNK_XMLSTAGO || kind == PNK_XMLETAGO)
     345             222 :                 str = cx->runtime->atomState.tagcAtom;
     346                 :         }
     347             576 :         if (str) {
     348             447 :             accum = js_ConcatStrings(cx, accum, str);
     349             447 :             if (!accum)
     350               0 :                 return JS_FALSE;
     351                 :         }
     352                 : 
     353             576 :         JS_ASSERT(*pnp == pn1);
     354            1346 :         while (pn1->pn_next) {
     355             194 :             pn1 = tc->freeTree(pn1);
     356             194 :             --pn->pn_count;
     357                 :         }
     358             576 :         pn1->setKind(PNK_XMLTEXT);
     359             576 :         pn1->setOp(JSOP_STRING);
     360             576 :         pn1->setArity(PN_NULLARY);
     361             576 :         pn1->pn_atom = js_AtomizeString(cx, accum);
     362             576 :         if (!pn1->pn_atom)
     363               0 :             return JS_FALSE;
     364             576 :         JS_ASSERT(pnp != &pn1->pn_next);
     365             576 :         *pnp = pn1;
     366                 :     }
     367                 : 
     368             576 :     if (pn1 && pn->pn_count == 1) {
     369                 :         /*
     370                 :          * Only one node under pn, and it has been folded: move pn1 onto pn
     371                 :          * unless pn is an XML root (in which case we need it to tell the code
     372                 :          * generator to emit a JSOP_TOXML or JSOP_TOXMLLIST op).  If pn is an
     373                 :          * XML root *and* it's a point-tag, rewrite it to PNK_XMLELEM to avoid
     374                 :          * extra "<" and "/>" bracketing at runtime.
     375                 :          */
     376             576 :         if (!(pn->pn_xflags & PNX_XMLROOT)) {
     377             277 :             pn->become(pn1);
     378             299 :         } else if (kind == PNK_XMLPTAGC) {
     379             180 :             pn->setKind(PNK_XMLELEM);
     380             180 :             pn->setOp(JSOP_TOXML);
     381                 :         }
     382                 :     }
     383             576 :     return JS_TRUE;
     384                 : }
     385                 : 
     386                 : #endif /* JS_HAS_XML_SUPPORT */
     387                 : 
     388                 : enum Truthiness { Truthy, Falsy, Unknown };
     389                 : 
     390                 : static Truthiness
     391         2072771 : Boolish(ParseNode *pn)
     392                 : {
     393         2072771 :     switch (pn->getOp()) {
     394                 :       case JSOP_DOUBLE:
     395              96 :         return (pn->pn_dval != 0 && !JSDOUBLE_IS_NaN(pn->pn_dval)) ? Truthy : Falsy;
     396                 : 
     397                 :       case JSOP_STRING:
     398               0 :         return (pn->pn_atom->length() > 0) ? Truthy : Falsy;
     399                 : 
     400                 : #if JS_HAS_GENERATOR_EXPRS
     401                 :       case JSOP_CALL:
     402                 :       {
     403                 :         /*
     404                 :          * A generator expression as an if or loop condition has no effects, it
     405                 :          * simply results in a truthy object reference. This condition folding
     406                 :          * is needed for the decompiler. See bug 442342 and bug 443074.
     407                 :          */
     408          237205 :         if (pn->pn_count != 1)
     409          146729 :             return Unknown;
     410           90476 :         ParseNode *pn2 = pn->pn_head;
     411           90476 :         if (!pn2->isKind(PNK_FUNCTION))
     412           90476 :             return Unknown;
     413               0 :         if (!(pn2->pn_funbox->tcflags & TCF_GENEXP_LAMBDA))
     414               0 :             return Unknown;
     415               0 :         return Truthy;
     416                 :       }
     417                 : #endif
     418                 : 
     419                 :       case JSOP_DEFFUN:
     420                 :       case JSOP_LAMBDA:
     421                 :       case JSOP_TRUE:
     422            1434 :         return Truthy;
     423                 : 
     424                 :       case JSOP_NULL:
     425                 :       case JSOP_FALSE:
     426              64 :         return Falsy;
     427                 : 
     428                 :       default:
     429         1833972 :         return Unknown;
     430                 :     }
     431                 : }
     432                 : 
     433                 : bool
     434        73010989 : js::FoldConstants(JSContext *cx, ParseNode *pn, TreeContext *tc, bool inCond)
     435                 : {
     436        73010989 :     ParseNode *pn1 = NULL, *pn2 = NULL, *pn3 = NULL;
     437                 : 
     438        73010989 :     JS_CHECK_RECURSION(cx, return false);
     439                 : 
     440        73010989 :     switch (pn->getArity()) {
     441                 :       case PN_FUNC:
     442                 :       {
     443          974634 :         uint32_t oldflags = tc->flags;
     444          974634 :         FunctionBox *oldlist = tc->functionList;
     445                 : 
     446          974634 :         tc->flags = pn->pn_funbox->tcflags;
     447          974634 :         tc->functionList = pn->pn_funbox->kids;
     448          974634 :         if (!FoldConstants(cx, pn->pn_body, tc))
     449               0 :             return false;
     450          974634 :         pn->pn_funbox->kids = tc->functionList;
     451          974634 :         tc->flags = oldflags;
     452          974634 :         tc->functionList = oldlist;
     453          974634 :         break;
     454                 :       }
     455                 : 
     456                 :       case PN_LIST:
     457                 :       {
     458                 :         /* Propagate inCond through logical connectives. */
     459         8617298 :         bool cond = inCond && (pn->isKind(PNK_OR) || pn->isKind(PNK_AND));
     460                 : 
     461                 :         /* Don't fold a parenthesized call expression. See bug 537673. */
     462         8617298 :         pn1 = pn2 = pn->pn_head;
     463         8617298 :         if ((pn->isKind(PNK_LP) || pn->isKind(PNK_NEW)) && pn2->isInParens())
     464            2894 :             pn2 = pn2->pn_next;
     465                 : 
     466                 :         /* Save the list head in pn1 for later use. */
     467        37576361 :         for (; pn2; pn2 = pn2->pn_next) {
     468        28959063 :             if (!FoldConstants(cx, pn2, tc, cond))
     469               0 :                 return false;
     470                 :         }
     471         8617298 :         break;
     472                 :       }
     473                 : 
     474                 :       case PN_TERNARY:
     475                 :         /* Any kid may be null (e.g. for (;;)). */
     476         1604467 :         pn1 = pn->pn_kid1;
     477         1604467 :         pn2 = pn->pn_kid2;
     478         1604467 :         pn3 = pn->pn_kid3;
     479         1604467 :         if (pn1 && !FoldConstants(cx, pn1, tc, pn->isKind(PNK_IF)))
     480               0 :             return false;
     481         1604467 :         if (pn2) {
     482         1363342 :             if (!FoldConstants(cx, pn2, tc, pn->isKind(PNK_FORHEAD)))
     483               0 :                 return false;
     484         1363342 :             if (pn->isKind(PNK_FORHEAD) && pn2->isOp(JSOP_TRUE)) {
     485               9 :                 tc->freeTree(pn2);
     486               9 :                 pn->pn_kid2 = NULL;
     487                 :             }
     488                 :         }
     489         1604467 :         if (pn3 && !FoldConstants(cx, pn3, tc))
     490               0 :             return false;
     491         1604467 :         break;
     492                 : 
     493                 :       case PN_BINARY:
     494         9057353 :         pn1 = pn->pn_left;
     495         9057353 :         pn2 = pn->pn_right;
     496                 : 
     497                 :         /* Propagate inCond through logical connectives. */
     498         9057353 :         if (pn->isKind(PNK_OR) || pn->isKind(PNK_AND)) {
     499          197018 :             if (!FoldConstants(cx, pn1, tc, inCond))
     500               0 :                 return false;
     501          197018 :             if (!FoldConstants(cx, pn2, tc, inCond))
     502               0 :                 return false;
     503          197018 :             break;
     504                 :         }
     505                 : 
     506                 :         /* First kid may be null (for default case in switch). */
     507         8860335 :         if (pn1 && !FoldConstants(cx, pn1, tc, pn->isKind(PNK_WHILE)))
     508               0 :             return false;
     509         8860335 :         if (!FoldConstants(cx, pn2, tc, pn->isKind(PNK_DOWHILE)))
     510               0 :             return false;
     511         8860335 :         break;
     512                 : 
     513                 :       case PN_UNARY:
     514         9534952 :         pn1 = pn->pn_kid;
     515                 : 
     516                 :         /*
     517                 :          * Kludge to deal with typeof expressions: because constant folding
     518                 :          * can turn an expression into a name node, we have to check here,
     519                 :          * before folding, to see if we should throw undefined name errors.
     520                 :          *
     521                 :          * NB: We know that if pn->pn_op is JSOP_TYPEOF, pn1 will not be
     522                 :          * null. This assumption does not hold true for other unary
     523                 :          * expressions.
     524                 :          */
     525         9534952 :         if (pn->isOp(JSOP_TYPEOF) && !pn1->isKind(PNK_NAME))
     526            4314 :             pn->setOp(JSOP_TYPEOFEXPR);
     527                 : 
     528         9534952 :         if (pn1 && !FoldConstants(cx, pn1, tc, pn->isOp(JSOP_NOT)))
     529               0 :             return false;
     530         9534952 :         break;
     531                 : 
     532                 :       case PN_NAME:
     533                 :         /*
     534                 :          * Skip pn1 down along a chain of dotted member expressions to avoid
     535                 :          * excessive recursion.  Our only goal here is to fold constants (if
     536                 :          * any) in the primary expression operand to the left of the first
     537                 :          * dot in the chain.
     538                 :          */
     539        26108910 :         if (!pn->isUsed()) {
     540        12202282 :             pn1 = pn->pn_expr;
     541        25763451 :             while (pn1 && pn1->isArity(PN_NAME) && !pn1->isUsed())
     542         1358887 :                 pn1 = pn1->pn_expr;
     543        12202282 :             if (pn1 && !FoldConstants(cx, pn1, tc))
     544               0 :                 return false;
     545                 :         }
     546        26108910 :         break;
     547                 : 
     548                 :       case PN_NAMESET:
     549          808270 :         pn1 = pn->pn_tree;
     550          808270 :         if (!FoldConstants(cx, pn1, tc))
     551               0 :             return false;
     552          808270 :         break;
     553                 : 
     554                 :       case PN_NULLARY:
     555        16305105 :         break;
     556                 :     }
     557                 : 
     558        73010989 :     switch (pn->getKind()) {
     559                 :       case PNK_IF:
     560          949064 :         if (ContainsVarOrConst(pn2) || ContainsVarOrConst(pn3))
     561           30881 :             break;
     562                 :         /* FALL THROUGH */
     563                 : 
     564                 :       case PNK_CONDITIONAL:
     565                 :         /* Reduce 'if (C) T; else E' into T for true C, E for false. */
     566          986419 :         switch (pn1->getKind()) {
     567                 :           case PNK_NUMBER:
     568               0 :             if (pn1->pn_dval == 0 || JSDOUBLE_IS_NaN(pn1->pn_dval))
     569               0 :                 pn2 = pn3;
     570               0 :             break;
     571                 :           case PNK_STRING:
     572               0 :             if (pn1->pn_atom->length() == 0)
     573               0 :                 pn2 = pn3;
     574               0 :             break;
     575                 :           case PNK_TRUE:
     576              36 :             break;
     577                 :           case PNK_FALSE:
     578                 :           case PNK_NULL:
     579              48 :             pn2 = pn3;
     580              48 :             break;
     581                 :           default:
     582                 :             /* Early return to dodge common code that copies pn2 to pn. */
     583          986335 :             return true;
     584                 :         }
     585                 : 
     586                 : #if JS_HAS_GENERATOR_EXPRS
     587                 :         /* Don't fold a trailing |if (0)| in a generator expression. */
     588              84 :         if (!pn2 && (tc->flags & TCF_GENEXP_LAMBDA))
     589               0 :             break;
     590                 : #endif
     591                 : 
     592              84 :         if (pn2 && !pn2->isDefn())
     593              36 :             pn->become(pn2);
     594              84 :         if (!pn2 || (pn->isKind(PNK_SEMI) && !pn->pn_kid)) {
     595                 :             /*
     596                 :              * False condition and no else, or an empty then-statement was
     597                 :              * moved up over pn.  Either way, make pn an empty block (not an
     598                 :              * empty statement, which does not decompile, even when labeled).
     599                 :              * NB: pn must be a PNK_IF as PNK_CONDITIONAL can never have a null
     600                 :              * kid or an empty statement for a child.
     601                 :              */
     602              48 :             pn->setKind(PNK_STATEMENTLIST);
     603              48 :             pn->setArity(PN_LIST);
     604              48 :             pn->makeEmpty();
     605                 :         }
     606              84 :         tc->freeTree(pn2);
     607              84 :         if (pn3 && pn3 != pn2)
     608               0 :             tc->freeTree(pn3);
     609              84 :         break;
     610                 : 
     611                 :       case PNK_OR:
     612                 :       case PNK_AND:
     613          229563 :         if (inCond) {
     614          174574 :             if (pn->isArity(PN_LIST)) {
     615           27561 :                 ParseNode **pnp = &pn->pn_head;
     616           27561 :                 JS_ASSERT(*pnp == pn1);
     617           91565 :                 do {
     618           91565 :                     Truthiness t = Boolish(pn1);
     619           91565 :                     if (t == Unknown) {
     620           91565 :                         pnp = &pn1->pn_next;
     621           91565 :                         continue;
     622                 :                     }
     623               0 :                     if ((t == Truthy) == pn->isKind(PNK_OR)) {
     624               0 :                         for (pn2 = pn1->pn_next; pn2; pn2 = pn3) {
     625               0 :                             pn3 = pn2->pn_next;
     626               0 :                             tc->freeTree(pn2);
     627               0 :                             --pn->pn_count;
     628                 :                         }
     629               0 :                         pn1->pn_next = NULL;
     630               0 :                         break;
     631                 :                     }
     632               0 :                     JS_ASSERT((t == Truthy) == pn->isKind(PNK_AND));
     633               0 :                     if (pn->pn_count == 1)
     634               0 :                         break;
     635               0 :                     *pnp = pn1->pn_next;
     636               0 :                     tc->freeTree(pn1);
     637               0 :                     --pn->pn_count;
     638                 :                 } while ((pn1 = *pnp) != NULL);
     639                 : 
     640                 :                 // We may have to change arity from LIST to BINARY.
     641           27561 :                 pn1 = pn->pn_head;
     642           27561 :                 if (pn->pn_count == 2) {
     643               0 :                     pn2 = pn1->pn_next;
     644               0 :                     pn1->pn_next = NULL;
     645               0 :                     JS_ASSERT(!pn2->pn_next);
     646               0 :                     pn->setArity(PN_BINARY);
     647               0 :                     pn->pn_left = pn1;
     648               0 :                     pn->pn_right = pn2;
     649           27561 :                 } else if (pn->pn_count == 1) {
     650               0 :                     pn->become(pn1);
     651               0 :                     tc->freeTree(pn1);
     652                 :                 }
     653                 :             } else {
     654          147013 :                 Truthiness t = Boolish(pn1);
     655          147013 :                 if (t != Unknown) {
     656               9 :                     if ((t == Truthy) == pn->isKind(PNK_OR)) {
     657               9 :                         tc->freeTree(pn2);
     658               9 :                         pn->become(pn1);
     659                 :                     } else {
     660               0 :                         JS_ASSERT((t == Truthy) == pn->isKind(PNK_AND));
     661               0 :                         tc->freeTree(pn1);
     662               0 :                         pn->become(pn2);
     663                 :                     }
     664                 :                 }
     665                 :             }
     666                 :         }
     667          229563 :         break;
     668                 : 
     669                 :       case PNK_SUBASSIGN:
     670                 :       case PNK_BITORASSIGN:
     671                 :       case PNK_BITXORASSIGN:
     672                 :       case PNK_BITANDASSIGN:
     673                 :       case PNK_LSHASSIGN:
     674                 :       case PNK_RSHASSIGN:
     675                 :       case PNK_URSHASSIGN:
     676                 :       case PNK_MULASSIGN:
     677                 :       case PNK_DIVASSIGN:
     678                 :       case PNK_MODASSIGN:
     679                 :         /*
     680                 :          * Compound operators such as *= should be subject to folding, in case
     681                 :          * the left-hand side is constant, and so that the decompiler produces
     682                 :          * the same string that you get from decompiling a script or function
     683                 :          * compiled from that same string.  += is special and so must be
     684                 :          * handled below.
     685                 :          */
     686           14779 :         goto do_binary_op;
     687                 : 
     688                 :       case PNK_ADDASSIGN:
     689           66407 :         JS_ASSERT(pn->isOp(JSOP_ADD));
     690                 :         /* FALL THROUGH */
     691                 :       case PNK_ADD:
     692          435008 :         if (pn->isArity(PN_LIST)) {
     693                 :             /*
     694                 :              * Any string literal term with all others number or string means
     695                 :              * this is a concatenation.  If any term is not a string or number
     696                 :              * literal, we can't fold.
     697                 :              */
     698          174251 :             JS_ASSERT(pn->pn_count > 2);
     699          174251 :             if (pn->pn_xflags & PNX_CANTFOLD)
     700          157096 :                 return true;
     701           17155 :             if (pn->pn_xflags != PNX_STRCAT)
     702               0 :                 goto do_binary_op;
     703                 : 
     704                 :             /* Ok, we're concatenating: convert non-string constant operands. */
     705           17155 :             size_t length = 0;
     706          114749 :             for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
     707           97594 :                 if (!FoldType(cx, pn2, PNK_STRING))
     708               0 :                     return false;
     709                 :                 /* XXX fold only if all operands convert to string */
     710           97594 :                 if (!pn2->isKind(PNK_STRING))
     711               0 :                     return true;
     712           97594 :                 length += pn2->pn_atom->length();
     713                 :             }
     714                 : 
     715                 :             /* Allocate a new buffer and string descriptor for the result. */
     716           17155 :             jschar *chars = (jschar *) cx->malloc_((length + 1) * sizeof(jschar));
     717           17155 :             if (!chars)
     718               0 :                 return false;
     719           17155 :             chars[length] = 0;
     720           17155 :             JSString *str = js_NewString(cx, chars, length);
     721           17155 :             if (!str) {
     722               0 :                 cx->free_(chars);
     723               0 :                 return false;
     724                 :             }
     725                 : 
     726                 :             /* Fill the buffer, advancing chars and recycling kids as we go. */
     727          114749 :             for (pn2 = pn1; pn2; pn2 = tc->freeTree(pn2)) {
     728           97594 :                 JSAtom *atom = pn2->pn_atom;
     729           97594 :                 size_t length2 = atom->length();
     730           97594 :                 js_strncpy(chars, atom->chars(), length2);
     731           97594 :                 chars += length2;
     732                 :             }
     733           17155 :             JS_ASSERT(*chars == 0);
     734                 : 
     735                 :             /* Atomize the result string and mutate pn to refer to it. */
     736           17155 :             pn->pn_atom = js_AtomizeString(cx, str);
     737           17155 :             if (!pn->pn_atom)
     738               0 :                 return false;
     739           17155 :             pn->setKind(PNK_STRING);
     740           17155 :             pn->setOp(JSOP_STRING);
     741           17155 :             pn->setArity(PN_NULLARY);
     742           17155 :             break;
     743                 :         }
     744                 : 
     745                 :         /* Handle a binary string concatenation. */
     746          260757 :         JS_ASSERT(pn->isArity(PN_BINARY));
     747          260757 :         if (pn1->isKind(PNK_STRING) || pn2->isKind(PNK_STRING)) {
     748                 :             JSString *left, *right, *str;
     749                 : 
     750          175774 :             if (!FoldType(cx, !pn1->isKind(PNK_STRING) ? pn1 : pn2, PNK_STRING))
     751               0 :                 return false;
     752          175774 :             if (!pn1->isKind(PNK_STRING) || !pn2->isKind(PNK_STRING))
     753          163618 :                 return true;
     754           12156 :             left = pn1->pn_atom;
     755           12156 :             right = pn2->pn_atom;
     756           12156 :             str = js_ConcatStrings(cx, left, right);
     757           12156 :             if (!str)
     758               0 :                 return false;
     759           12156 :             pn->pn_atom = js_AtomizeString(cx, str);
     760           12156 :             if (!pn->pn_atom)
     761               0 :                 return false;
     762           12156 :             pn->setKind(PNK_STRING);
     763           12156 :             pn->setOp(JSOP_STRING);
     764           12156 :             pn->setArity(PN_NULLARY);
     765           12156 :             tc->freeTree(pn1);
     766           12156 :             tc->freeTree(pn2);
     767           12156 :             break;
     768                 :         }
     769                 : 
     770                 :         /* Can't concatenate string literals, let's try numbers. */
     771           84983 :         goto do_binary_op;
     772                 : 
     773                 :       case PNK_SUB:
     774                 :       case PNK_STAR:
     775                 :       case PNK_LSH:
     776                 :       case PNK_RSH:
     777                 :       case PNK_URSH:
     778                 :       case PNK_DIV:
     779                 :       case PNK_MOD:
     780                 :       do_binary_op:
     781          165578 :         if (pn->isArity(PN_LIST)) {
     782             729 :             JS_ASSERT(pn->pn_count > 2);
     783            3132 :             for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
     784            2403 :                 if (!FoldType(cx, pn2, PNK_NUMBER))
     785               0 :                     return false;
     786                 :             }
     787            1453 :             for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
     788                 :                 /* XXX fold only if all operands convert to number */
     789            1275 :                 if (!pn2->isKind(PNK_NUMBER))
     790             551 :                     break;
     791                 :             }
     792             729 :             if (!pn2) {
     793             178 :                 JSOp op = pn->getOp();
     794                 : 
     795             178 :                 pn2 = pn1->pn_next;
     796             178 :                 pn3 = pn2->pn_next;
     797             178 :                 if (!FoldBinaryNumeric(cx, op, pn1, pn2, pn, tc))
     798               0 :                     return false;
     799             611 :                 while ((pn2 = pn3) != NULL) {
     800             255 :                     pn3 = pn2->pn_next;
     801             255 :                     if (!FoldBinaryNumeric(cx, op, pn, pn2, pn, tc))
     802               0 :                         return false;
     803                 :                 }
     804                 :             }
     805                 :         } else {
     806          164849 :             JS_ASSERT(pn->isArity(PN_BINARY));
     807          329698 :             if (!FoldType(cx, pn1, PNK_NUMBER) ||
     808          164849 :                 !FoldType(cx, pn2, PNK_NUMBER)) {
     809               0 :                 return false;
     810                 :             }
     811          164849 :             if (pn1->isKind(PNK_NUMBER) && pn2->isKind(PNK_NUMBER)) {
     812             891 :                 if (!FoldBinaryNumeric(cx, pn->getOp(), pn1, pn2, pn, tc))
     813               0 :                     return false;
     814                 :             }
     815                 :         }
     816          165578 :         break;
     817                 : 
     818                 :       case PNK_TYPEOF:
     819                 :       case PNK_VOID:
     820                 :       case PNK_NOT:
     821                 :       case PNK_BITNOT:
     822                 :       case PNK_POS:
     823                 :       case PNK_NEG:
     824          490618 :         if (pn1->isKind(PNK_NUMBER)) {
     825                 :             double d;
     826                 : 
     827                 :             /* Operate on one numeric constant. */
     828           83967 :             d = pn1->pn_dval;
     829           83967 :             switch (pn->getOp()) {
     830                 :               case JSOP_BITNOT:
     831               0 :                 d = ~js_DoubleToECMAInt32(d);
     832               0 :                 break;
     833                 : 
     834                 :               case JSOP_NEG:
     835           82795 :                 d = -d;
     836           82795 :                 break;
     837                 : 
     838                 :               case JSOP_POS:
     839               2 :                 break;
     840                 : 
     841                 :               case JSOP_NOT:
     842               0 :                 if (d == 0 || JSDOUBLE_IS_NaN(d)) {
     843               0 :                     pn->setKind(PNK_TRUE);
     844               0 :                     pn->setOp(JSOP_TRUE);
     845                 :                 } else {
     846               0 :                     pn->setKind(PNK_FALSE);
     847               0 :                     pn->setOp(JSOP_FALSE);
     848                 :                 }
     849               0 :                 pn->setArity(PN_NULLARY);
     850                 :                 /* FALL THROUGH */
     851                 : 
     852                 :               default:
     853                 :                 /* Return early to dodge the common PNK_NUMBER code. */
     854            1170 :                 return true;
     855                 :             }
     856           82797 :             pn->setKind(PNK_NUMBER);
     857           82797 :             pn->setOp(JSOP_DOUBLE);
     858           82797 :             pn->setArity(PN_NULLARY);
     859           82797 :             pn->pn_dval = d;
     860           82797 :             tc->freeTree(pn1);
     861          406651 :         } else if (pn1->isKind(PNK_TRUE) || pn1->isKind(PNK_FALSE)) {
     862              27 :             if (pn->isOp(JSOP_NOT)) {
     863               9 :                 pn->become(pn1);
     864               9 :                 if (pn->isKind(PNK_TRUE)) {
     865               0 :                     pn->setKind(PNK_FALSE);
     866               0 :                     pn->setOp(JSOP_FALSE);
     867                 :                 } else {
     868               9 :                     pn->setKind(PNK_TRUE);
     869               9 :                     pn->setOp(JSOP_TRUE);
     870                 :                 }
     871               9 :                 tc->freeTree(pn1);
     872                 :             }
     873                 :         }
     874          489448 :         break;
     875                 : 
     876                 : #if JS_HAS_XML_SUPPORT
     877                 :       case PNK_XMLELEM:
     878                 :       case PNK_XMLLIST:
     879                 :       case PNK_XMLPTAGC:
     880                 :       case PNK_XMLSTAGO:
     881                 :       case PNK_XMLETAGO:
     882                 :       case PNK_XMLNAME:
     883            1032 :         if (pn->isArity(PN_LIST)) {
     884             576 :             JS_ASSERT(pn->isKind(PNK_XMLLIST) || pn->pn_count != 0);
     885             576 :             if (!FoldXMLConstants(cx, pn, tc))
     886               0 :                 return false;
     887                 :         }
     888            1032 :         break;
     889                 : 
     890                 :       case PNK_AT:
     891               9 :         if (pn1->isKind(PNK_XMLNAME)) {
     892               0 :             Value v = StringValue(pn1->pn_atom);
     893               0 :             if (!js_ToAttributeName(cx, &v))
     894               0 :                 return false;
     895               0 :             JS_ASSERT(v.isObject());
     896                 : 
     897               0 :             ObjectBox *xmlbox = tc->parser->newObjectBox(&v.toObject());
     898               0 :             if (!xmlbox)
     899               0 :                 return false;
     900                 : 
     901               0 :             pn->setKind(PNK_XMLNAME);
     902               0 :             pn->setOp(JSOP_OBJECT);
     903               0 :             pn->setArity(PN_NULLARY);
     904               0 :             pn->pn_objbox = xmlbox;
     905               0 :             tc->freeTree(pn1);
     906                 :         }
     907               9 :         break;
     908                 : #endif /* JS_HAS_XML_SUPPORT */
     909                 : 
     910                 :       default:;
     911                 :     }
     912                 : 
     913        71702770 :     if (inCond) {
     914         1834193 :         Truthiness t = Boolish(pn);
     915         1834193 :         if (t != Unknown) {
     916                 :             /*
     917                 :              * We can turn function nodes into constant nodes here, but mutating function
     918                 :              * nodes is tricky --- in particular, mutating a function node that appears on
     919                 :              * a method list corrupts the method list. However, methods are M's in
     920                 :              * statements of the form 'this.foo = M;', which we never fold, so we're okay.
     921                 :              */
     922            1585 :             tc->parser->allocator.prepareNodeForMutation(pn);
     923            1585 :             if (t == Truthy) {
     924            1465 :                 pn->setKind(PNK_TRUE);
     925            1465 :                 pn->setOp(JSOP_TRUE);
     926                 :             } else {
     927             120 :                 pn->setKind(PNK_FALSE);
     928             120 :                 pn->setOp(JSOP_FALSE);
     929                 :             }
     930            1585 :             pn->setArity(PN_NULLARY);
     931                 :         }
     932                 :     }
     933                 : 
     934        71702770 :     return true;
     935                 : }

Generated by: LCOV version 1.7