tor-browser

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

BytecodeCompiler.h (11972B)


      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_BytecodeCompiler_h
      8 #define frontend_BytecodeCompiler_h
      9 
     10 #include "mozilla/AlreadyAddRefed.h"  // already_AddRefed
     11 #include "mozilla/Maybe.h"            // mozilla::Maybe
     12 #include "mozilla/Utf8.h"             // mozilla::Utf8Unit
     13 
     14 #include <stdint.h>  // uint32_t
     15 
     16 #include "ds/LifoAlloc.h"                 // js::LifoAlloc
     17 #include "frontend/FunctionSyntaxKind.h"  // FunctionSyntaxKind
     18 #include "frontend/ScriptIndex.h"         // ScriptIndex
     19 #include "js/CompileOptions.h"  // JS::ReadOnlyCompileOptions, JS::PrefableCompileOptions
     20 #include "js/GCVector.h"    // JS::StackGCVector
     21 #include "js/Id.h"          // JS::PropertyKey
     22 #include "js/RootingAPI.h"  // JS::Handle
     23 #include "js/SourceText.h"  // JS::SourceText
     24 #include "js/UniquePtr.h"   // js::UniquePtr
     25 #include "js/Value.h"       // JS::Value
     26 #include "vm/ScopeKind.h"   // js::ScopeKind
     27 
     28 /*
     29 * Structure of all of the support classes.
     30 *
     31 * Parser: described in Parser.h.
     32 *
     33 * BytecodeCompiler.cpp: BytecodeCompiler.h
     34 * This is the "driver", the high-level operations like "compile this source to
     35 * bytecode". It calls the parser, bytecode emitter, etc.
     36 *
     37 * ParseContext.h and SharedContext.h: Both have similar purposes. They're split
     38 * because ParseContext contains information used only by the parser, and
     39 * SharedContext contains information used by both the parser and
     40 * BytecodeEmitter.
     41 *
     42 * SharedContext.h: class Directives: this contains boolean flags for tracking
     43 * if we're in asm.js or "use strict" code. The "use strict" bit is stored in
     44 * SharedContext, and additionally, the full Directives class is stored in
     45 * ParseContext - if a direcive is encountered while parsing, this is updated,
     46 * and checked in GeneralParser::functionDefinition, and if it changed, the
     47 * whole function is re-parsed with the new flags.
     48 *
     49 * SharedContext.h: abstract class SharedContext: This class contains two
     50 * different groups of flags:
     51 *
     52 * Parse context information. This is information conceptually "passed down"
     53 * into parsing sub-nodes. This is like "are we parsing strict code?", and so
     54 * the parser can make decisions of how to parse based off that.
     55 *
     56 * Gathered-while-parsing information. This is information conceptually
     57 * "returned up" from parsing sub-nodes. This is like "did we see a use strict
     58 * directive"?
     59 *
     60 * Additionally, subclasses (GlobalSharedContext, ModuleSharedContext,
     61 * EvalSharedContext, and FunctionBox) contain binding information, scope
     62 * information, and other such bits of data.
     63 *
     64 * ParseContext.h: class UsedNameTracker: Track which bindings are used in which
     65 * scopes. This helps determine which bindings are closed-over, which affects
     66 * how they're stored; and whether special bindings like `this` and `arguments`
     67 * can be optimized away.
     68 *
     69 * ParseContext.h: class ParseContext: Extremely complex class that serves a lot
     70 * of purposes, but it's a single class - essentially no derived classes - so
     71 * it's a little easier to comprehend all at once. (SourceParseContext does
     72 * derive from ParseContext, but they does nothing except adjust the
     73 * constructor's arguments).
     74 * Note it uses a thing called Nestable, which implements a stack of objects:
     75 * you can push (and pop) instances to a stack (linked list) as you parse
     76 * further into the parse tree. You may push to this stack via calling the
     77 * constructor with a GeneralParser as an argument (usually `this`), which
     78 * pushes itself onto `this->pc` (so it does get assigned/pushed, even though no
     79 * assignment ever appears directly in the parser)
     80 *
     81 * ParseContext contains a pointer to a SharedContext.
     82 *
     83 * There's a decent chunk of flags/data collection in here too, some "pass-down"
     84 * data and some "return-up" data.
     85 *
     86 * ParseContext also contains a significant number of *sub*-Nestables as fields
     87 * of itself (nestables inside nestables). Note you also push/pop to these via
     88 * passing `Parser->pc`, which the constructor of the sub-nestable knows which
     89 * ParseContext field to push to. The sub-nestables are:
     90 *
     91 * ParseContext::Statement: stack of statements.
     92 * `if (x) { while (true) { try { ..stack of [if, while, try].. } ... } }`
     93 *
     94 * ParseContext::LabelStatement: interspersed in Statement stack, for labeled
     95 * statements, for e.g. `label: while (true) { break label; }`
     96 *
     97 * ParseContext::ClassStatement: interspersed in Statement stack, for classes
     98 * the parser is currently inside of.
     99 *
    100 * ParseContext::Scope: Set of variables in each scope (stack of sets):
    101 * `{ let a; let b; { let c; } }`
    102 * (this gets complicated with `var`, etc., check the class for docs)
    103 */
    104 
    105 class JSFunction;
    106 class JSObject;
    107 class JSScript;
    108 struct JSContext;
    109 
    110 namespace js {
    111 
    112 class ModuleObject;
    113 class FrontendContext;
    114 class Scope;
    115 
    116 namespace frontend {
    117 
    118 struct CompilationInput;
    119 struct CompilationStencil;
    120 struct ExtensibleCompilationStencil;
    121 struct InitialStencilAndDelazifications;
    122 struct CompilationGCOutput;
    123 class ScopeBindingCache;
    124 
    125 // Compile a script of the given source using the given CompilationInput.
    126 extern already_AddRefed<CompilationStencil>
    127 CompileGlobalScriptToStencilWithInput(JSContext* maybeCx, FrontendContext* fc,
    128                                      js::LifoAlloc& tempLifoAlloc,
    129                                      CompilationInput& input,
    130                                      ScopeBindingCache* scopeCache,
    131                                      JS::SourceText<mozilla::Utf8Unit>& srcBuf,
    132                                      ScopeKind scopeKind);
    133 
    134 [[nodiscard]] extern bool InstantiateStencils(JSContext* cx,
    135                                              CompilationInput& input,
    136                                              const CompilationStencil& stencil,
    137                                              CompilationGCOutput& gcOutput);
    138 
    139 [[nodiscard]] extern bool InstantiateStencils(
    140    JSContext* cx, CompilationInput& input,
    141    InitialStencilAndDelazifications& stencils, CompilationGCOutput& gcOutput);
    142 
    143 // Perform CompileGlobalScriptToStencil and InstantiateStencils at the
    144 // same time, skipping some extra copy.
    145 extern JSScript* CompileGlobalScript(JSContext* cx, FrontendContext* fc,
    146                                     const JS::ReadOnlyCompileOptions& options,
    147                                     JS::SourceText<char16_t>& srcBuf,
    148                                     ScopeKind scopeKind);
    149 
    150 extern JSScript* CompileGlobalScript(JSContext* cx, FrontendContext* fc,
    151                                     const JS::ReadOnlyCompileOptions& options,
    152                                     JS::SourceText<mozilla::Utf8Unit>& srcBuf,
    153                                     ScopeKind scopeKind);
    154 
    155 // Compile a script with a list of known extra bindings.
    156 //
    157 // Bindings should be passed by a pair of unwrappedBindingKeys and
    158 // unwrappedBindingValues.
    159 //
    160 // If any of the bindings are accessed by the script, a WithEnvironmentObject
    161 // is created for the bindings and returned via env out parameter. Otherwise,
    162 // global lexical is returned. In both case, the same env must be used to
    163 // evaluate the script.
    164 //
    165 // Both unwrappedBindingKeys and unwrappedBindingValues can come from different
    166 // realm than the current realm.
    167 //
    168 // If a binding is shadowed by the global variables declared by the script,
    169 // or the existing global variables, the binding is not stored into the
    170 // resulting WithEnvironmentObject.
    171 extern JSScript* CompileGlobalScriptWithExtraBindings(
    172    JSContext* cx, FrontendContext* fc,
    173    const JS::ReadOnlyCompileOptions& options, JS::SourceText<char16_t>& srcBuf,
    174    JS::Handle<JS::StackGCVector<JS::PropertyKey>> unwrappedBindingKeys,
    175    JS::Handle<JS::StackGCVector<JS::Value>> unwrappedBindingValues,
    176    JS::MutableHandle<JSObject*> env);
    177 
    178 // Compile a script for eval of the given source using the given options and
    179 // enclosing scope/environment.
    180 extern JSScript* CompileEvalScript(JSContext* cx,
    181                                   const JS::ReadOnlyCompileOptions& options,
    182                                   JS::SourceText<char16_t>& srcBuf,
    183                                   JS::Handle<js::Scope*> enclosingScope,
    184                                   JS::Handle<JSObject*> enclosingEnv);
    185 
    186 // Compile a module of the given source using the given options.
    187 ModuleObject* CompileModule(JSContext* cx, FrontendContext* fc,
    188                            const JS::ReadOnlyCompileOptions& options,
    189                            JS::SourceText<char16_t>& srcBuf);
    190 ModuleObject* CompileModule(JSContext* cx, FrontendContext* fc,
    191                            const JS::ReadOnlyCompileOptions& options,
    192                            JS::SourceText<mozilla::Utf8Unit>& srcBuf);
    193 
    194 //
    195 // Compile a single function. The source in srcBuf must match the ECMA-262
    196 // FunctionExpression production.
    197 //
    198 // If nonzero, parameterListEnd is the offset within srcBuf where the parameter
    199 // list is expected to end. During parsing, if we find that it ends anywhere
    200 // else, it's a SyntaxError. This is used to implement the Function constructor;
    201 // it's how we detect that these weird cases are SyntaxErrors:
    202 //
    203 //     Function("/*", "*/x) {")
    204 //     Function("x){ if (3", "return x;}")
    205 //
    206 [[nodiscard]] JSFunction* CompileStandaloneFunction(
    207    JSContext* cx, const JS::ReadOnlyCompileOptions& options,
    208    JS::SourceText<char16_t>& srcBuf,
    209    const mozilla::Maybe<uint32_t>& parameterListEnd,
    210    frontend::FunctionSyntaxKind syntaxKind);
    211 
    212 [[nodiscard]] JSFunction* CompileStandaloneGenerator(
    213    JSContext* cx, const JS::ReadOnlyCompileOptions& options,
    214    JS::SourceText<char16_t>& srcBuf,
    215    const mozilla::Maybe<uint32_t>& parameterListEnd,
    216    frontend::FunctionSyntaxKind syntaxKind);
    217 
    218 [[nodiscard]] JSFunction* CompileStandaloneAsyncFunction(
    219    JSContext* cx, const JS::ReadOnlyCompileOptions& options,
    220    JS::SourceText<char16_t>& srcBuf,
    221    const mozilla::Maybe<uint32_t>& parameterListEnd,
    222    frontend::FunctionSyntaxKind syntaxKind);
    223 
    224 [[nodiscard]] JSFunction* CompileStandaloneAsyncGenerator(
    225    JSContext* cx, const JS::ReadOnlyCompileOptions& options,
    226    JS::SourceText<char16_t>& srcBuf,
    227    const mozilla::Maybe<uint32_t>& parameterListEnd,
    228    frontend::FunctionSyntaxKind syntaxKind);
    229 
    230 // Compile a single function in given enclosing non-syntactic scope.
    231 [[nodiscard]] JSFunction* CompileStandaloneFunctionInNonSyntacticScope(
    232    JSContext* cx, const JS::ReadOnlyCompileOptions& options,
    233    JS::SourceText<char16_t>& srcBuf,
    234    const mozilla::Maybe<uint32_t>& parameterListEnd,
    235    frontend::FunctionSyntaxKind syntaxKind, JS::Handle<Scope*> enclosingScope);
    236 
    237 extern bool DelazifyCanonicalScriptedFunction(JSContext* cx,
    238                                              FrontendContext* fc,
    239                                              JS::Handle<JSFunction*> fun);
    240 
    241 enum class DelazifyFailureReason {
    242  Compressed,
    243  Other,
    244 };
    245 
    246 // Delazify a function specified by a pair of `context` + `scriptIndex`, and
    247 // store the delazification stencil into `stencils`, and return a borrowing
    248 // pointer for the delazification.
    249 extern const CompilationStencil* DelazifyCanonicalScriptedFunction(
    250    FrontendContext* fc, js::LifoAlloc& tempLifoAlloc,
    251    const JS::PrefableCompileOptions& prefableOptions,
    252    ScopeBindingCache* scopeCache, ScriptIndex scriptIndex,
    253    InitialStencilAndDelazifications* stencils,
    254    DelazifyFailureReason* failureReason);
    255 
    256 // Certain compile options will disable the syntax parser entirely.
    257 inline bool CanLazilyParse(const JS::ReadOnlyCompileOptions& options) {
    258  return !options.discardSource && !options.sourceIsLazy &&
    259         !options.forceFullParse();
    260 }
    261 
    262 } /* namespace frontend */
    263 } /* namespace js */
    264 
    265 #endif /* frontend_BytecodeCompiler_h */