tor-browser

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

FunctionEmitter.h (15549B)


      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 #ifndef frontend_FunctionEmitter_h
      8 #define frontend_FunctionEmitter_h
      9 
     10 #include "mozilla/Attributes.h"  // MOZ_STACK_CLASS
     11 
     12 #include <stdint.h>  // uint16_t, uint32_t
     13 
     14 #include "frontend/AsyncEmitter.h"        // AsyncEmitter
     15 #include "frontend/DefaultEmitter.h"      // DefaultEmitter
     16 #include "frontend/EmitterScope.h"        // EmitterScope
     17 #include "frontend/FunctionSyntaxKind.h"  // FunctionSyntaxKind
     18 #include "frontend/ParserAtom.h"          // TaggedParserAtomIndex
     19 #include "frontend/TDZCheckCache.h"       // TDZCheckCache
     20 
     21 namespace js {
     22 
     23 class GCThingIndex;
     24 
     25 namespace frontend {
     26 
     27 struct BytecodeEmitter;
     28 class FunctionBox;
     29 
     30 // Class for emitting function declaration, expression, or method etc.
     31 //
     32 // This class handles the enclosing script's part (function object creation,
     33 // declaration, etc). The content of the function script is handled by
     34 // FunctionScriptEmitter and FunctionParamsEmitter.
     35 //
     36 // Usage: (check for the return value is omitted for simplicity)
     37 //
     38 //   `function f() {}`, non lazy script
     39 //     FunctionEmitter fe(this, funbox_for_f, FunctionSyntaxKind::Statement,
     40 //                        FunctionEmitter::IsHoisted::No);
     41 //     fe.prepareForNonLazy();
     42 //
     43 //     // Emit script with FunctionScriptEmitter here.
     44 //     ...
     45 //
     46 //     fe.emitNonLazyEnd();
     47 //
     48 //   `function f() {}`, lazy script
     49 //     FunctionEmitter fe(this, funbox_for_f, FunctionSyntaxKind::Statement,
     50 //                        FunctionEmitter::IsHoisted::No);
     51 //     fe.emitLazy();
     52 //
     53 //   `function f() {}`, emitting hoisted function again
     54 //     // See emitAgain comment for more details
     55 //     FunctionEmitter fe(this, funbox_for_f, FunctionSyntaxKind::Statement,
     56 //                        FunctionEmitter::IsHoisted::Yes);
     57 //     fe.emitAgain();
     58 //
     59 //   `function f() { "use asm"; }`
     60 //     FunctionEmitter fe(this, funbox_for_f, FunctionSyntaxKind::Statement,
     61 //                        FunctionEmitter::IsHoisted::No);
     62 //     fe.emitAsmJSModule();
     63 //
     64 class MOZ_STACK_CLASS FunctionEmitter {
     65 public:
     66  enum class IsHoisted { No, Yes };
     67 
     68 private:
     69  BytecodeEmitter* bce_;
     70 
     71  FunctionBox* funbox_;
     72 
     73  // Function's explicit name.
     74  TaggedParserAtomIndex name_;
     75 
     76  FunctionSyntaxKind syntaxKind_;
     77  IsHoisted isHoisted_;
     78 
     79 #ifdef DEBUG
     80  // The state of this emitter.
     81  //
     82  // +-------+
     83  // | Start |-+
     84  // +-------+ |
     85  //           |
     86  //   +-------+
     87  //   |
     88  //   | [non-lazy function]
     89  //   |   prepareForNonLazy  +---------+ emitNonLazyEnd     +-----+
     90  //   +--------------------->| NonLazy |---------------->+->| End |
     91  //   |                      +---------+                 ^  +-----+
     92  //   |                                                  |
     93  //   | [lazy function]                                  |
     94  //   |   emitLazy                                       |
     95  //   +------------------------------------------------->+
     96  //   |                                                  ^
     97  //   | [emitting hoisted function again]                |
     98  //   |   emitAgain                                      |
     99  //   +------------------------------------------------->+
    100  //   |                                                  ^
    101  //   | [asm.js module]                                  |
    102  //   |   emitAsmJSModule                                |
    103  //   +--------------------------------------------------+
    104  //
    105  enum class State {
    106    // The initial state.
    107    Start,
    108 
    109    // After calling prepareForNonLazy.
    110    NonLazy,
    111 
    112    // After calling emitNonLazyEnd, emitLazy, emitAgain, or emitAsmJSModule.
    113    End
    114  };
    115  State state_ = State::Start;
    116 #endif
    117 
    118 public:
    119  FunctionEmitter(BytecodeEmitter* bce, FunctionBox* funbox,
    120                  FunctionSyntaxKind syntaxKind, IsHoisted isHoisted);
    121 
    122  [[nodiscard]] bool prepareForNonLazy();
    123  [[nodiscard]] bool emitNonLazyEnd();
    124 
    125  [[nodiscard]] bool emitLazy();
    126 
    127  [[nodiscard]] bool emitAgain();
    128 
    129  [[nodiscard]] bool emitAsmJSModule();
    130 
    131 private:
    132  // Emit the function declaration, expression, method etc.
    133  // This leaves function object on the stack for expression etc,
    134  // and doesn't for declaration.
    135  [[nodiscard]] bool emitFunction();
    136 
    137  // Helper methods used by emitFunction for each case.
    138  // `index` is the object index of the function.
    139  [[nodiscard]] bool emitNonHoisted(GCThingIndex index);
    140  [[nodiscard]] bool emitHoisted(GCThingIndex index);
    141  [[nodiscard]] bool emitTopLevelFunction(GCThingIndex index);
    142 };
    143 
    144 // Class for emitting function script.
    145 // Parameters are handled by FunctionParamsEmitter.
    146 //
    147 // Usage: (check for the return value is omitted for simplicity)
    148 //
    149 //   `function f(a) { expr }`
    150 //     FunctionScriptEmitter fse(this, funbox_for_f,
    151 //                               Some(offset_of_opening_paren),
    152 //                               Some(offset_of_closing_brace));
    153 //     fse.prepareForParameters();
    154 //
    155 //     // Emit parameters with FunctionParamsEmitter here.
    156 //     ...
    157 //
    158 //     fse.prepareForBody();
    159 //     emit(expr);
    160 //     fse.emitEnd();
    161 //
    162 //     // Do NameFunctions operation here if needed.
    163 //
    164 //     fse.intoStencil();
    165 //
    166 class MOZ_STACK_CLASS FunctionScriptEmitter {
    167 private:
    168  BytecodeEmitter* bce_;
    169 
    170  FunctionBox* funbox_;
    171 
    172  // Scope for the function name for a named lambda.
    173  // None for anonymous function.
    174  mozilla::Maybe<EmitterScope> namedLambdaEmitterScope_;
    175 
    176  // Scope for function body.
    177  mozilla::Maybe<EmitterScope> functionEmitterScope_;
    178 
    179  // Scope for the extra body var.
    180  // None if `funbox_->hasExtraBodyVarScope() == false`.
    181  mozilla::Maybe<EmitterScope> extraBodyVarEmitterScope_;
    182 
    183  mozilla::Maybe<TDZCheckCache> tdzCache_;
    184 
    185  // try-catch block for async function parameter and body.
    186  mozilla::Maybe<AsyncEmitter> asyncEmitter_;
    187 
    188  // See the comment for constructor.
    189  mozilla::Maybe<uint32_t> paramStart_;
    190  mozilla::Maybe<uint32_t> bodyEnd_;
    191 
    192 #ifdef DEBUG
    193  // The state of this emitter.
    194  //
    195  // +-------+ prepareForParameters  +------------+
    196  // | Start |---------------------->| Parameters |-+
    197  // +-------+                       +------------+ |
    198  //                                                |
    199  //   +--------------------------------------------+
    200  //   |
    201  //   | prepareForBody  +------+ emitEndBody  +---------+
    202  //   +---------------->| Body |------------->| EndBody |-+
    203  //                     +------+              +---------+ |
    204  //                                                       |
    205  //     +-------------------------------------------------+
    206  //     |
    207  //     | intoStencil +-----+
    208  //     +------------>| End |
    209  //                   +-----+
    210  enum class State {
    211    // The initial state.
    212    Start,
    213 
    214    // After calling prepareForParameters.
    215    Parameters,
    216 
    217    // After calling prepareForBody.
    218    Body,
    219 
    220    // After calling emitEndBody.
    221    EndBody,
    222 
    223    // After calling intoStencil.
    224    End
    225  };
    226  State state_ = State::Start;
    227 #endif
    228 
    229 public:
    230  // Parameters are the offset in the source code for each character below:
    231  //
    232  //   function f(a, b, ...c) { ... }
    233  //             ^                  ^
    234  //             |                  |
    235  //             paramStart         bodyEnd
    236  //
    237  // Can be Nothing() if not available.
    238  FunctionScriptEmitter(BytecodeEmitter* bce, FunctionBox* funbox,
    239                        const mozilla::Maybe<uint32_t>& paramStart,
    240                        const mozilla::Maybe<uint32_t>& bodyEnd)
    241      : bce_(bce),
    242        funbox_(funbox),
    243        paramStart_(paramStart),
    244        bodyEnd_(bodyEnd) {}
    245 
    246  [[nodiscard]] bool prepareForParameters();
    247  [[nodiscard]] bool prepareForBody();
    248  [[nodiscard]] bool emitEndBody();
    249 
    250  // Generate the ScriptStencil using the bytecode emitter data.
    251  [[nodiscard]] bool intoStencil();
    252 
    253 private:
    254  [[nodiscard]] bool emitExtraBodyVarScope();
    255  [[nodiscard]] bool emitInitializeClosedOverArgumentBindings();
    256 };
    257 
    258 // Class for emitting function parameters.
    259 //
    260 // Usage: (check for the return value is omitted for simplicity)
    261 //
    262 //   `function f(a, b=10, ...c) {}`
    263 //     FunctionParamsEmitter fpe(this, funbox_for_f);
    264 //
    265 //     fpe.emitSimple(atom_of_a);
    266 //
    267 //     fpe.prepareForDefault();
    268 //     emit(10);
    269 //     fpe.emitDefaultEnd(atom_of_b);
    270 //
    271 //     fpe.emitRest(atom_of_c);
    272 //
    273 //   `function f([a], [b]=[1], ...[c]) {}`
    274 //     FunctionParamsEmitter fpe(this, funbox_for_f);
    275 //
    276 //     fpe.prepareForDestructuring();
    277 //     emit(destructuring_for_[a]);
    278 //     fpe.emitDestructuringEnd();
    279 //
    280 //     fpe.prepareForDestructuringDefaultInitializer();
    281 //     emit([1]);
    282 //     fpe.prepareForDestructuringDefault();
    283 //     emit(destructuring_for_[b]);
    284 //     fpe.emitDestructuringDefaultEnd();
    285 //
    286 //     fpe.prepareForDestructuringRest();
    287 //     emit(destructuring_for_[c]);
    288 //     fpe.emitDestructuringRestEnd();
    289 //
    290 class MOZ_STACK_CLASS FunctionParamsEmitter {
    291 private:
    292  BytecodeEmitter* bce_;
    293 
    294  FunctionBox* funbox_;
    295 
    296  // The pointer to `FunctionScriptEmitter::functionEmitterScope_`,
    297  // passed via `BytecodeEmitter::innermostEmitterScope()`.
    298  EmitterScope* functionEmitterScope_;
    299 
    300  // The slot for the current parameter.
    301  // NOTE: after emitting rest parameter, this isn't incremented.
    302  uint16_t argSlot_ = 0;
    303 
    304  // DefaultEmitter for default parameter.
    305  mozilla::Maybe<DefaultEmitter> default_;
    306 
    307 #ifdef DEBUG
    308  // The state of this emitter.
    309  //
    310  // +----------------------------------------------------------+
    311  // |                                                          |
    312  // |  +-------+                                               |
    313  // +->| Start |-+                                             |
    314  //    +-------+ |                                             |
    315  //              |                                             |
    316  // +------------+                                             |
    317  // |                                                          |
    318  // | [single binding, without default]                        |
    319  // |   emitSimple                                             |
    320  // +--------------------------------------------------------->+
    321  // |                                                          ^
    322  // | [single binding, with default]                           |
    323  // |   prepareForDefault  +---------+ emitDefaultEnd          |
    324  // +--------------------->| Default |------------------------>+
    325  // |                      +---------+                         ^
    326  // |                                                          |
    327  // | [destructuring, without default]                         |
    328  // |   prepareForDestructuring  +---------------+             |
    329  // +--------------------------->| Destructuring |-+           |
    330  // |                            +---------------+ |           |
    331  // |                                              |           |
    332  // |    +-----------------------------------------+           |
    333  // |    |                                                     |
    334  // |    | emitDestructuringEnd                                |
    335  // |    +---------------------------------------------------->+
    336  // |                                                          ^
    337  // | [destructuring, with default]                            |
    338  // |   prepareForDestructuringDefaultInitializer              |
    339  // +---------------------------------------------+            |
    340  // |                                             |            |
    341  // |    +----------------------------------------+            |
    342  // |    |                                                     |
    343  // |    |  +---------------------------------+                |
    344  // |    +->| DestructuringDefaultInitializer |-+              |
    345  // |       +---------------------------------+ |              |
    346  // |                                           |              |
    347  // |      +------------------------------------+              |
    348  // |      |                                                   |
    349  // |      | prepareForDestructuringDefault                    |
    350  // |      +-------------------------------+                   |
    351  // |                                      |                   |
    352  // |        +-----------------------------+                   |
    353  // |        |                                                 |
    354  // |        |  +----------------------+                       |
    355  // |        +->| DestructuringDefault |-+                     |
    356  // |           +----------------------+ |                     |
    357  // |                                    |                     |
    358  // |          +-------------------------+                     |
    359  // |          |                                               |
    360  // |          | emitDestructuringDefaultEnd                   |
    361  // |          +---------------------------------------------->+
    362  // |
    363  // | [single binding rest]
    364  // |   emitRest                                                  +-----+
    365  // +--------------------------------------------------------->+->| End |
    366  // |                                                          ^  +-----+
    367  // | [destructuring rest]                                     |
    368  // |   prepareForDestructuringRest   +-------------------+    |
    369  // +-------------------------------->| DestructuringRest |-+  |
    370  //                                   +-------------------+ |  |
    371  //                                                         |  |
    372  //    +----------------------------------------------------+  |
    373  //    |                                                       |
    374  //    | emitDestructuringRestEnd                              |
    375  //    +-------------------------------------------------------+
    376  //
    377  enum class State {
    378    // The initial state, or after emitting non-rest parameter.
    379    Start,
    380 
    381    // After calling prepareForDefault.
    382    Default,
    383 
    384    // After calling prepareForDestructuring.
    385    Destructuring,
    386 
    387    // After calling prepareForDestructuringDefaultInitializer.
    388    DestructuringDefaultInitializer,
    389 
    390    // After calling prepareForDestructuringDefault.
    391    DestructuringDefault,
    392 
    393    // After calling prepareForDestructuringRest.
    394    DestructuringRest,
    395 
    396    // After calling emitRest or emitDestructuringRestEnd.
    397    End,
    398  };
    399  State state_ = State::Start;
    400 #endif
    401 
    402 public:
    403  FunctionParamsEmitter(BytecodeEmitter* bce, FunctionBox* funbox);
    404 
    405  // paramName is used only when there's at least one expression in the
    406  // paramerters (funbox_->hasParameterExprs == true).
    407  [[nodiscard]] bool emitSimple(TaggedParserAtomIndex paramName);
    408 
    409  [[nodiscard]] bool prepareForDefault();
    410  [[nodiscard]] bool emitDefaultEnd(TaggedParserAtomIndex paramName);
    411 
    412  [[nodiscard]] bool prepareForDestructuring();
    413  [[nodiscard]] bool emitDestructuringEnd();
    414 
    415  [[nodiscard]] bool prepareForDestructuringDefaultInitializer();
    416  [[nodiscard]] bool prepareForDestructuringDefault();
    417  [[nodiscard]] bool emitDestructuringDefaultEnd();
    418 
    419  [[nodiscard]] bool emitRest(TaggedParserAtomIndex paramName);
    420 
    421  [[nodiscard]] bool prepareForDestructuringRest();
    422  [[nodiscard]] bool emitDestructuringRestEnd();
    423 
    424 private:
    425  [[nodiscard]] bool prepareForInitializer();
    426  [[nodiscard]] bool emitInitializerEnd();
    427 
    428  [[nodiscard]] bool emitRestArray();
    429 
    430  [[nodiscard]] bool emitAssignment(TaggedParserAtomIndex paramName);
    431 };
    432 
    433 } /* namespace frontend */
    434 } /* namespace js */
    435 
    436 #endif /* frontend_FunctionEmitter_h */