tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ParseNode.cpp (14541B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "frontend/ParseNode.h"
      8 
      9 #include "mozilla/Try.h"  // MOZ_TRY*
     10 
     11 #include "jsnum.h"
     12 
     13 #include "frontend/CompilationStencil.h"  // ExtensibleCompilationStencil
     14 #include "frontend/FullParseHandler.h"
     15 #include "frontend/ParseContext.h"
     16 #include "frontend/Parser.h"      // ParserBase
     17 #include "frontend/ParserAtom.h"  // ParserAtomsTable, TaggedParserAtomIndex
     18 #include "frontend/SharedContext.h"
     19 #include "js/Printer.h"
     20 #include "vm/Scope.h"  // GetScopeDataTrailingNames
     21 
     22 using namespace js;
     23 using namespace js::frontend;
     24 
     25 #ifdef DEBUG
     26 void ListNode::checkConsistency() const {
     27  ParseNode* const* tailNode;
     28  uint32_t actualCount = 0;
     29  if (const ParseNode* last = head()) {
     30    const ParseNode* pn = last;
     31    while (pn) {
     32      last = pn;
     33      pn = pn->pn_next;
     34      actualCount++;
     35    }
     36 
     37    tailNode = &last->pn_next;
     38  } else {
     39    tailNode = &head_;
     40  }
     41  MOZ_ASSERT(tail() == tailNode);
     42  MOZ_ASSERT(count() == actualCount);
     43 }
     44 #endif
     45 
     46 /*
     47 * Allocate a ParseNode from parser's node freelist or, failing that, from
     48 * cx's temporary arena.
     49 */
     50 void* ParseNodeAllocator::allocNode(size_t size) {
     51  LifoAlloc::AutoFallibleScope fallibleAllocator(&alloc);
     52  void* p = alloc.alloc(size);
     53  if (!p) {
     54    ReportOutOfMemory(fc);
     55  }
     56  return p;
     57 }
     58 
     59 ParseNodeResult ParseNode::appendOrCreateList(ParseNodeKind kind,
     60                                              ParseNode* left, ParseNode* right,
     61                                              FullParseHandler* handler,
     62                                              ParseContext* pc) {
     63  // The asm.js specification is written in ECMAScript grammar terms that
     64  // specify *only* a binary tree.  It's a royal pain to implement the asm.js
     65  // spec to act upon n-ary lists as created below.  So for asm.js, form a
     66  // binary tree of lists exactly as ECMAScript would by skipping the
     67  // following optimization.
     68  if (!pc->useAsmOrInsideUseAsm()) {
     69    // Left-associative trees of a given operator (e.g. |a + b + c|) are
     70    // binary trees in the spec: (+ (+ a b) c) in Lisp terms.  Recursively
     71    // processing such a tree, exactly implemented that way, would blow the
     72    // the stack.  We use a list node that uses O(1) stack to represent
     73    // such operations: (+ a b c).
     74    //
     75    // (**) is right-associative; per spec |a ** b ** c| parses as
     76    // (** a (** b c)). But we treat this the same way, creating a list
     77    // node: (** a b c). All consumers must understand that this must be
     78    // processed with a right fold, whereas the list (+ a b c) must be
     79    // processed with a left fold because (+) is left-associative.
     80    //
     81    if (left->isKind(kind) &&
     82        (kind == ParseNodeKind::PowExpr ? !left->isInParens()
     83                                        : left->isBinaryOperation())) {
     84      ListNode* list = &left->as<ListNode>();
     85 
     86      list->append(right);
     87      list->pn_pos.end = right->pn_pos.end;
     88 
     89      return list;
     90    }
     91  }
     92 
     93  ListNode* list = MOZ_TRY(handler->newResult<ListNode>(kind, left));
     94 
     95  list->append(right);
     96  return list;
     97 }
     98 
     99 const ParseNode::TypeCode ParseNode::typeCodeTable[] = {
    100 #define TYPE_CODE(_name, type) type::classTypeCode(),
    101    FOR_EACH_PARSE_NODE_KIND(TYPE_CODE)
    102 #undef TYPE_CODE
    103 };
    104 
    105 #ifdef DEBUG
    106 
    107 const size_t ParseNode::sizeTable[] = {
    108 #  define NODE_SIZE(_name, type) sizeof(type),
    109    FOR_EACH_PARSE_NODE_KIND(NODE_SIZE)
    110 #  undef NODE_SIZE
    111 };
    112 
    113 static const char* const parseNodeNames[] = {
    114 #  define STRINGIFY(name, _type) #name,
    115    FOR_EACH_PARSE_NODE_KIND(STRINGIFY)
    116 #  undef STRINGIFY
    117 };
    118 
    119 static void DumpParseTree(const ParserAtomsTable* parserAtoms, ParseNode* pn,
    120                          GenericPrinter& out, int indent) {
    121  if (pn == nullptr) {
    122    out.put("#NULL");
    123  } else {
    124    pn->dump(parserAtoms, out, indent);
    125  }
    126 }
    127 
    128 void frontend::DumpParseTree(ParserBase* parser, ParseNode* pn,
    129                             GenericPrinter& out, int indent) {
    130  ParserAtomsTable* parserAtoms = parser ? &parser->parserAtoms() : nullptr;
    131  ::DumpParseTree(parserAtoms, pn, out, indent);
    132 }
    133 
    134 static void IndentNewLine(GenericPrinter& out, int indent) {
    135  out.putChar('\n');
    136  for (int i = 0; i < indent; ++i) {
    137    out.putChar(' ');
    138  }
    139 }
    140 
    141 void ParseNode::dump() { dump(nullptr); }
    142 
    143 void ParseNode::dump(const ParserAtomsTable* parserAtoms) {
    144  js::Fprinter out(stderr);
    145  dump(parserAtoms, out);
    146 }
    147 
    148 void ParseNode::dump(const ParserAtomsTable* parserAtoms, GenericPrinter& out) {
    149  dump(parserAtoms, out, 0);
    150  out.putChar('\n');
    151 }
    152 
    153 void ParseNode::dump(const ParserAtomsTable* parserAtoms, GenericPrinter& out,
    154                     int indent) {
    155  switch (getKind()) {
    156 #  define DUMP(K, T)                              \
    157    case ParseNodeKind::K:                        \
    158      as<T>().dumpImpl(parserAtoms, out, indent); \
    159      break;
    160    FOR_EACH_PARSE_NODE_KIND(DUMP)
    161 #  undef DUMP
    162    default:
    163      out.printf("#<BAD NODE %p, kind=%u>", (void*)this, unsigned(getKind()));
    164  }
    165 }
    166 
    167 void NullaryNode::dumpImpl(const ParserAtomsTable* parserAtoms,
    168                           GenericPrinter& out, int indent) {
    169  switch (getKind()) {
    170    case ParseNodeKind::TrueExpr:
    171      out.put("#true");
    172      break;
    173    case ParseNodeKind::FalseExpr:
    174      out.put("#false");
    175      break;
    176    case ParseNodeKind::NullExpr:
    177      out.put("#null");
    178      break;
    179    case ParseNodeKind::RawUndefinedExpr:
    180      out.put("#undefined");
    181      break;
    182 
    183    default:
    184      out.printf("(%s)", parseNodeNames[getKindAsIndex()]);
    185  }
    186 }
    187 
    188 void NumericLiteral::dumpImpl(const ParserAtomsTable* parserAtoms,
    189                              GenericPrinter& out, int indent) {
    190  ToCStringBuf cbuf;
    191  const char* cstr = NumberToCString(&cbuf, value());
    192  MOZ_ASSERT(cstr);
    193  if (!std::isfinite(value())) {
    194    out.put("#");
    195  }
    196  out.printf("%s", cstr);
    197 }
    198 
    199 void BigIntLiteral::dumpImpl(const ParserAtomsTable* parserAtoms,
    200                             GenericPrinter& out, int indent) {
    201  out.printf("(%s)", parseNodeNames[getKindAsIndex()]);
    202 }
    203 
    204 void RegExpLiteral::dumpImpl(const ParserAtomsTable* parserAtoms,
    205                             GenericPrinter& out, int indent) {
    206  out.printf("(%s)", parseNodeNames[getKindAsIndex()]);
    207 }
    208 
    209 static void DumpCharsNoNewline(const ParserAtomsTable* parserAtoms,
    210                               TaggedParserAtomIndex index,
    211                               GenericPrinter& out) {
    212  out.put("\"");
    213  if (parserAtoms) {
    214    parserAtoms->dumpCharsNoQuote(out, index);
    215  } else {
    216    DumpTaggedParserAtomIndexNoQuote(out, index, nullptr);
    217  }
    218  out.put("\"");
    219 }
    220 
    221 void LoopControlStatement::dumpImpl(const ParserAtomsTable* parserAtoms,
    222                                    GenericPrinter& out, int indent) {
    223  const char* name = parseNodeNames[getKindAsIndex()];
    224  out.printf("(%s", name);
    225  if (label_) {
    226    out.printf(" ");
    227    DumpCharsNoNewline(parserAtoms, label_, out);
    228  }
    229  out.printf(")");
    230 }
    231 
    232 void UnaryNode::dumpImpl(const ParserAtomsTable* parserAtoms,
    233                         GenericPrinter& out, int indent) {
    234  const char* name = parseNodeNames[getKindAsIndex()];
    235  out.printf("(%s ", name);
    236  indent += strlen(name) + 2;
    237  ::DumpParseTree(parserAtoms, kid(), out, indent);
    238  out.printf(")");
    239 }
    240 
    241 void BinaryNode::dumpImpl(const ParserAtomsTable* parserAtoms,
    242                          GenericPrinter& out, int indent) {
    243  if (isKind(ParseNodeKind::DotExpr)) {
    244    out.put("(.");
    245 
    246    ::DumpParseTree(parserAtoms, right(), out, indent + 2);
    247 
    248    out.putChar(' ');
    249    if (as<PropertyAccess>().isSuper()) {
    250      out.put("super");
    251    } else {
    252      ::DumpParseTree(parserAtoms, left(), out, indent + 2);
    253    }
    254 
    255    out.printf(")");
    256    return;
    257  }
    258 
    259  const char* name = parseNodeNames[getKindAsIndex()];
    260  out.printf("(%s ", name);
    261  indent += strlen(name) + 2;
    262  ::DumpParseTree(parserAtoms, left(), out, indent);
    263  IndentNewLine(out, indent);
    264  ::DumpParseTree(parserAtoms, right(), out, indent);
    265  out.printf(")");
    266 }
    267 
    268 void TernaryNode::dumpImpl(const ParserAtomsTable* parserAtoms,
    269                           GenericPrinter& out, int indent) {
    270  const char* name = parseNodeNames[getKindAsIndex()];
    271  out.printf("(%s ", name);
    272  indent += strlen(name) + 2;
    273  ::DumpParseTree(parserAtoms, kid1(), out, indent);
    274  IndentNewLine(out, indent);
    275  ::DumpParseTree(parserAtoms, kid2(), out, indent);
    276  IndentNewLine(out, indent);
    277  ::DumpParseTree(parserAtoms, kid3(), out, indent);
    278  out.printf(")");
    279 }
    280 
    281 void FunctionNode::dumpImpl(const ParserAtomsTable* parserAtoms,
    282                            GenericPrinter& out, int indent) {
    283  const char* name = parseNodeNames[getKindAsIndex()];
    284  out.printf("(%s ", name);
    285  indent += strlen(name) + 2;
    286  ::DumpParseTree(parserAtoms, body(), out, indent);
    287  out.printf(")");
    288 }
    289 
    290 void ModuleNode::dumpImpl(const ParserAtomsTable* parserAtoms,
    291                          GenericPrinter& out, int indent) {
    292  const char* name = parseNodeNames[getKindAsIndex()];
    293  out.printf("(%s ", name);
    294  indent += strlen(name) + 2;
    295  ::DumpParseTree(parserAtoms, body(), out, indent);
    296  out.printf(")");
    297 }
    298 
    299 void ListNode::dumpImpl(const ParserAtomsTable* parserAtoms,
    300                        GenericPrinter& out, int indent) {
    301  const char* name = parseNodeNames[getKindAsIndex()];
    302  out.printf("(%s [", name);
    303  if (ParseNode* listHead = head()) {
    304    indent += strlen(name) + 3;
    305    ::DumpParseTree(parserAtoms, listHead, out, indent);
    306    for (ParseNode* item : contentsFrom(listHead->pn_next)) {
    307      IndentNewLine(out, indent);
    308      ::DumpParseTree(parserAtoms, item, out, indent);
    309    }
    310  }
    311  out.printf("])");
    312 }
    313 
    314 void NameNode::dumpImpl(const ParserAtomsTable* parserAtoms,
    315                        GenericPrinter& out, int indent) {
    316  switch (getKind()) {
    317    case ParseNodeKind::StringExpr:
    318    case ParseNodeKind::TemplateStringExpr:
    319    case ParseNodeKind::ObjectPropertyName:
    320      DumpCharsNoNewline(parserAtoms, atom_, out);
    321      return;
    322 
    323    case ParseNodeKind::Name:
    324    case ParseNodeKind::PrivateName:  // atom() already includes the '#', no
    325                                      // need to specially include it.
    326    case ParseNodeKind::PropertyNameExpr:
    327      if (!atom_) {
    328        out.put("#<null name>");
    329      } else if (parserAtoms) {
    330        if (atom_ == TaggedParserAtomIndex::WellKnown::empty()) {
    331          out.put("#<zero-length name>");
    332        } else {
    333          parserAtoms->dumpCharsNoQuote(out, atom_);
    334        }
    335      } else {
    336        DumpTaggedParserAtomIndexNoQuote(out, atom_, nullptr);
    337      }
    338      return;
    339 
    340    case ParseNodeKind::LabelStmt: {
    341      this->as<LabeledStatement>().dumpImpl(parserAtoms, out, indent);
    342      return;
    343    }
    344 
    345    default: {
    346      const char* name = parseNodeNames[getKindAsIndex()];
    347      out.printf("(%s)", name);
    348      return;
    349    }
    350  }
    351 }
    352 
    353 void LabeledStatement::dumpImpl(const ParserAtomsTable* parserAtoms,
    354                                GenericPrinter& out, int indent) {
    355  const char* name = parseNodeNames[getKindAsIndex()];
    356  out.printf("(%s ", name);
    357  DumpCharsNoNewline(parserAtoms, label(), out);
    358  indent += strlen(name) + 2;
    359  IndentNewLine(out, indent);
    360  ::DumpParseTree(parserAtoms, statement(), out, indent);
    361  out.printf(")");
    362 }
    363 
    364 template <ParseNodeKind Kind, typename ScopeType>
    365 void BaseScopeNode<Kind, ScopeType>::dumpImpl(
    366    const ParserAtomsTable* parserAtoms, GenericPrinter& out, int indent) {
    367  const char* name = parseNodeNames[getKindAsIndex()];
    368  out.printf("(%s [", name);
    369  int nameIndent = indent + strlen(name) + 3;
    370  if (!isEmptyScope()) {
    371    typename ScopeType::ParserData* bindings = scopeBindings();
    372    auto names = GetScopeDataTrailingNames(bindings);
    373    for (uint32_t i = 0; i < names.size(); i++) {
    374      auto index = names[i].name();
    375      if (parserAtoms) {
    376        if (index == TaggedParserAtomIndex::WellKnown::empty()) {
    377          out.put("#<zero-length name>");
    378        } else {
    379          parserAtoms->dumpCharsNoQuote(out, index);
    380        }
    381      } else {
    382        DumpTaggedParserAtomIndexNoQuote(out, index, nullptr);
    383      }
    384      if (i < names.size() - 1) {
    385        IndentNewLine(out, nameIndent);
    386      }
    387    }
    388  }
    389  out.putChar(']');
    390  indent += 2;
    391  IndentNewLine(out, indent);
    392  ::DumpParseTree(parserAtoms, scopeBody(), out, indent);
    393  out.printf(")");
    394 }
    395 
    396 #  ifdef ENABLE_DECORATORS
    397 void ClassMethod::dumpImpl(const ParserAtomsTable* parserAtoms,
    398                           GenericPrinter& out, int indent) {
    399  if (decorators_) {
    400    decorators_->dumpImpl(parserAtoms, out, indent);
    401  }
    402  Base::dumpImpl(parserAtoms, out, indent);
    403 }
    404 
    405 void ClassField::dumpImpl(const ParserAtomsTable* parserAtoms,
    406                          GenericPrinter& out, int indent) {
    407  if (decorators_) {
    408    decorators_->dumpImpl(parserAtoms, out, indent);
    409    out.putChar(' ');
    410  }
    411  Base::dumpImpl(parserAtoms, out, indent);
    412  IndentNewLine(out, indent + 2);
    413  if (accessorGetterNode_) {
    414    out.printf("getter: ");
    415    accessorGetterNode_->dumpImpl(parserAtoms, out, indent);
    416  }
    417  IndentNewLine(out, indent + 2);
    418  if (accessorSetterNode_) {
    419    out.printf("setter: ");
    420    accessorSetterNode_->dumpImpl(parserAtoms, out, indent);
    421  }
    422 }
    423 
    424 void ClassNode::dumpImpl(const ParserAtomsTable* parserAtoms,
    425                         GenericPrinter& out, int indent) {
    426  if (decorators_) {
    427    decorators_->dumpImpl(parserAtoms, out, indent);
    428  }
    429  Base::dumpImpl(parserAtoms, out, indent);
    430 }
    431 #  endif
    432 
    433 #endif
    434 
    435 TaggedParserAtomIndex NumericLiteral::toAtom(
    436    FrontendContext* fc, ParserAtomsTable& parserAtoms) const {
    437  return NumberToParserAtom(fc, parserAtoms, value());
    438 }
    439 
    440 RegExpObject* RegExpLiteral::create(
    441    JSContext* cx, FrontendContext* fc, ParserAtomsTable& parserAtoms,
    442    CompilationAtomCache& atomCache,
    443    ExtensibleCompilationStencil& stencil) const {
    444  return stencil.regExpData[index_].createRegExpAndEnsureAtom(
    445      cx, fc, parserAtoms, atomCache);
    446 }
    447 
    448 bool js::frontend::IsAnonymousFunctionDefinition(ParseNode* pn) {
    449  // ES 2017 draft
    450  // 12.15.2 (ArrowFunction, AsyncArrowFunction).
    451  // 14.1.12 (FunctionExpression).
    452  // 14.4.8 (Generatoression).
    453  // 14.6.8 (AsyncFunctionExpression)
    454  if (pn->is<FunctionNode>() &&
    455      !pn->as<FunctionNode>().funbox()->explicitName()) {
    456    return true;
    457  }
    458 
    459  // 14.5.8 (ClassExpression)
    460  if (pn->is<ClassNode>() && !pn->as<ClassNode>().names()) {
    461    return true;
    462  }
    463 
    464  return false;
    465 }