tor-browser

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

SharedContext.cpp (15141B)


      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/SharedContext.h"
      8 
      9 #include "frontend/CompilationStencil.h"
     10 #include "frontend/FunctionSyntaxKind.h"  // FunctionSyntaxKind
     11 #include "frontend/ModuleSharedContext.h"
     12 #include "frontend/ParseContext.h"
     13 #include "frontend/ParseNode.h"
     14 #include "frontend/ParserAtom.h"
     15 #include "frontend/ScopeIndex.h"
     16 #include "frontend/ScriptIndex.h"
     17 #include "frontend/Stencil.h"
     18 #include "js/CompileOptions.h"
     19 #include "js/Vector.h"
     20 #include "vm/FunctionFlags.h"          // js::FunctionFlags
     21 #include "vm/GeneratorAndAsyncKind.h"  // js::GeneratorKind, js::FunctionAsyncKind
     22 #include "vm/JSScript.h"  // js::FillImmutableFlagsFromCompileOptionsForTopLevel, js::FillImmutableFlagsFromCompileOptionsForFunction
     23 #include "vm/StencilEnums.h"  // ImmutableScriptFlagsEnum
     24 
     25 #include "frontend/ParseContext-inl.h"
     26 
     27 namespace js {
     28 
     29 class ModuleBuilder;
     30 
     31 namespace frontend {
     32 
     33 SharedContext::SharedContext(FrontendContext* fc, Kind kind,
     34                             const JS::ReadOnlyCompileOptions& options,
     35                             Directives directives, SourceExtent extent)
     36    : fc_(fc),
     37      extent_(extent),
     38      allowNewTarget_(false),
     39      allowSuperProperty_(false),
     40      allowSuperCall_(false),
     41      allowArguments_(true),
     42      inWith_(false),
     43      inClass_(false),
     44      localStrict(false),
     45      hasExplicitUseStrict_(false),
     46      isScriptExtraFieldCopiedToStencil(false),
     47      eligibleForArgumentsLength(true) {
     48  // Compute the script kind "input" flags.
     49  if (kind == Kind::FunctionBox) {
     50    setFlag(ImmutableFlags::IsFunction);
     51  } else if (kind == Kind::Module) {
     52    MOZ_ASSERT(!options.nonSyntacticScope);
     53    setFlag(ImmutableFlags::IsModule);
     54  } else if (kind == Kind::Eval) {
     55    setFlag(ImmutableFlags::IsForEval);
     56  } else {
     57    MOZ_ASSERT(kind == Kind::Global);
     58  }
     59 
     60  // Initialize the transitive "input" flags. These are applied to all
     61  // SharedContext in this compilation and generally cannot be determined from
     62  // the source text alone.
     63  if (isTopLevelContext()) {
     64    js::FillImmutableFlagsFromCompileOptionsForTopLevel(options,
     65                                                        immutableFlags_);
     66  } else {
     67    js::FillImmutableFlagsFromCompileOptionsForFunction(options,
     68                                                        immutableFlags_);
     69  }
     70 
     71  // Initialize the strict flag. This may be updated by the parser as we observe
     72  // further directives in the body.
     73  setFlag(ImmutableFlags::Strict, directives.strict());
     74 }
     75 
     76 GlobalSharedContext::GlobalSharedContext(
     77    FrontendContext* fc, ScopeKind scopeKind,
     78    const JS::ReadOnlyCompileOptions& options, Directives directives,
     79    SourceExtent extent)
     80    : SharedContext(fc, Kind::Global, options, directives, extent),
     81      scopeKind_(scopeKind),
     82      bindings(nullptr) {
     83  MOZ_ASSERT(scopeKind == ScopeKind::Global ||
     84             scopeKind == ScopeKind::NonSyntactic);
     85  MOZ_ASSERT(thisBinding_ == ThisBinding::Global);
     86 }
     87 
     88 EvalSharedContext::EvalSharedContext(FrontendContext* fc,
     89                                     CompilationState& compilationState,
     90                                     SourceExtent extent)
     91    : SharedContext(fc, Kind::Eval, compilationState.input.options,
     92                    compilationState.directives, extent),
     93      bindings(nullptr) {
     94  // Eval inherits syntax and binding rules from enclosing environment.
     95  allowNewTarget_ = compilationState.scopeContext.allowNewTarget;
     96  allowSuperProperty_ = compilationState.scopeContext.allowSuperProperty;
     97  allowSuperCall_ = compilationState.scopeContext.allowSuperCall;
     98  allowArguments_ = compilationState.scopeContext.allowArguments;
     99  thisBinding_ = compilationState.scopeContext.thisBinding;
    100  inWith_ = compilationState.scopeContext.inWith;
    101 }
    102 
    103 SuspendableContext::SuspendableContext(
    104    FrontendContext* fc, Kind kind, const JS::ReadOnlyCompileOptions& options,
    105    Directives directives, SourceExtent extent, bool isGenerator, bool isAsync)
    106    : SharedContext(fc, kind, options, directives, extent) {
    107  setFlag(ImmutableFlags::IsGenerator, isGenerator);
    108  setFlag(ImmutableFlags::IsAsync, isAsync);
    109 }
    110 
    111 FunctionBox::FunctionBox(FrontendContext* fc, SourceExtent extent,
    112                         CompilationState& compilationState,
    113                         Directives directives, GeneratorKind generatorKind,
    114                         FunctionAsyncKind asyncKind, bool isInitialCompilation,
    115                         TaggedParserAtomIndex atom, FunctionFlags flags,
    116                         ScriptIndex index)
    117    : SuspendableContext(fc, Kind::FunctionBox, compilationState.input.options,
    118                         directives, extent,
    119                         generatorKind == GeneratorKind::Generator,
    120                         asyncKind == FunctionAsyncKind::AsyncFunction),
    121      compilationState_(compilationState),
    122      atom_(atom),
    123      funcDataIndex_(index),
    124      flags_(FunctionFlags::clearMutableflags(flags)),
    125      emitBytecode(false),
    126      wasEmittedByEnclosingScript_(false),
    127      isAnnexB(false),
    128      useAsm(false),
    129      hasParameterExprs(false),
    130      hasDestructuringArgs(false),
    131      hasDuplicateParameters(false),
    132      hasExprBody_(false),
    133      allowReturn_(true),
    134      isFunctionFieldCopiedToStencil(false),
    135      isInitialCompilation(isInitialCompilation),
    136      isStandalone(false) {}
    137 
    138 void FunctionBox::initFromLazyFunction(const ScriptStencilExtra& extra,
    139                                       ScopeContext& scopeContext,
    140                                       FunctionSyntaxKind kind) {
    141  initFromScriptStencilExtra(extra);
    142  initStandaloneOrLazy(scopeContext, kind);
    143 }
    144 
    145 void FunctionBox::initFromScriptStencilExtra(const ScriptStencilExtra& extra) {
    146  immutableFlags_ = extra.immutableFlags;
    147  extent_ = extra.extent;
    148 }
    149 
    150 void FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing,
    151                                                FunctionSyntaxKind kind) {
    152  SharedContext* sc = enclosing->sc();
    153 
    154  // HasModuleGoal and useAsm are inherited from enclosing context.
    155  useAsm = sc->isFunctionBox() && sc->asFunctionBox()->useAsmOrInsideUseAsm();
    156  setHasModuleGoal(sc->hasModuleGoal());
    157 
    158  // Arrow functions don't have their own `this` binding.
    159  if (flags_.isArrow()) {
    160    allowNewTarget_ = sc->allowNewTarget();
    161    allowSuperProperty_ = sc->allowSuperProperty();
    162    allowSuperCall_ = sc->allowSuperCall();
    163    allowArguments_ = sc->allowArguments();
    164    thisBinding_ = sc->thisBinding();
    165  } else {
    166    if (IsConstructorKind(kind)) {
    167      // Record this function into the enclosing class statement so that
    168      // finishClassConstructor can final processing. Due to aborted syntax
    169      // parses (eg, because of asm.js), this may have already been set with an
    170      // early FunctionBox. In that case, the FunctionNode should still match.
    171      auto classStmt =
    172          enclosing->findInnermostStatement<ParseContext::ClassStatement>();
    173      MOZ_ASSERT(classStmt);
    174      MOZ_ASSERT(classStmt->constructorBox == nullptr ||
    175                 classStmt->constructorBox->functionNode == this->functionNode);
    176      classStmt->constructorBox = this;
    177    }
    178 
    179    allowNewTarget_ = true;
    180    allowSuperProperty_ = flags_.allowSuperProperty();
    181 
    182    if (kind == FunctionSyntaxKind::DerivedClassConstructor) {
    183      setDerivedClassConstructor();
    184      allowSuperCall_ = true;
    185      thisBinding_ = ThisBinding::DerivedConstructor;
    186    } else {
    187      thisBinding_ = ThisBinding::Function;
    188    }
    189 
    190    if (kind == FunctionSyntaxKind::FieldInitializer ||
    191        kind == FunctionSyntaxKind::StaticClassBlock) {
    192      setSyntheticFunction();
    193      allowArguments_ = false;
    194      if (kind == FunctionSyntaxKind::StaticClassBlock) {
    195        allowSuperCall_ = false;
    196        allowReturn_ = false;
    197      }
    198    }
    199  }
    200 
    201  if (sc->inWith()) {
    202    inWith_ = true;
    203  } else {
    204    auto isWith = [](ParseContext::Statement* stmt) {
    205      return stmt->kind() == StatementKind::With;
    206    };
    207 
    208    inWith_ = enclosing->findInnermostStatement(isWith);
    209  }
    210 
    211  if (sc->inClass()) {
    212    inClass_ = true;
    213  } else {
    214    auto isClass = [](ParseContext::Statement* stmt) {
    215      return stmt->kind() == StatementKind::Class;
    216    };
    217 
    218    inClass_ = enclosing->findInnermostStatement(isClass);
    219  }
    220 }
    221 
    222 void FunctionBox::initStandalone(ScopeContext& scopeContext,
    223                                 FunctionSyntaxKind kind) {
    224  initStandaloneOrLazy(scopeContext, kind);
    225 
    226  isStandalone = true;
    227 }
    228 
    229 void FunctionBox::initStandaloneOrLazy(ScopeContext& scopeContext,
    230                                       FunctionSyntaxKind kind) {
    231  if (flags_.isArrow()) {
    232    allowNewTarget_ = scopeContext.allowNewTarget;
    233    allowSuperProperty_ = scopeContext.allowSuperProperty;
    234    allowSuperCall_ = scopeContext.allowSuperCall;
    235    allowArguments_ = scopeContext.allowArguments;
    236    thisBinding_ = scopeContext.thisBinding;
    237  } else {
    238    allowNewTarget_ = true;
    239    allowSuperProperty_ = flags_.allowSuperProperty();
    240 
    241    if (kind == FunctionSyntaxKind::DerivedClassConstructor) {
    242      setDerivedClassConstructor();
    243      allowSuperCall_ = true;
    244      thisBinding_ = ThisBinding::DerivedConstructor;
    245    } else {
    246      thisBinding_ = ThisBinding::Function;
    247    }
    248 
    249    if (kind == FunctionSyntaxKind::FieldInitializer) {
    250      setSyntheticFunction();
    251      allowArguments_ = false;
    252    }
    253  }
    254 
    255  inWith_ = scopeContext.inWith;
    256  inClass_ = scopeContext.inClass;
    257 }
    258 
    259 void FunctionBox::setEnclosingScopeForInnerLazyFunction(ScopeIndex scopeIndex) {
    260  // For lazy functions inside a function which is being compiled, we cache
    261  // the incomplete scope object while compiling, and store it to the
    262  // BaseScript once the enclosing script successfully finishes compilation
    263  // in FunctionBox::finish.
    264  MOZ_ASSERT(enclosingScopeIndex_.isNothing());
    265  enclosingScopeIndex_ = mozilla::Some(scopeIndex);
    266  if (isFunctionFieldCopiedToStencil) {
    267    copyUpdatedEnclosingScopeIndex();
    268  }
    269 }
    270 
    271 bool FunctionBox::setUseAsm() {
    272  MOZ_ASSERT(!useAsm);
    273 
    274  // Mark this function as being in "use asm".
    275  useAsm = true;
    276 
    277  // Initialize the stencil asm.js container eagerly. We do this before
    278  // we validate/compile so that we can use the presence of this container to
    279  // fire a use counter that works even if asm.js is disabled and the function
    280  // doesn't end up being compiled with asm.js optimizations.
    281  //
    282  // This field is used to disable network and in-memory caching of stencils,
    283  // and so we will be effectively disabling those even if this asm.js
    284  // compilation fails or asm.js was disabled. Disabling asm.js is a non-
    285  // standard configuration and so this is expected to be quite rare.
    286  if (compilationState_.asmJS) {
    287    return true;
    288  }
    289  compilationState_.asmJS = fc_->getAllocator()->new_<StencilAsmJSContainer>();
    290  return !!compilationState_.asmJS;
    291 }
    292 
    293 bool FunctionBox::setAsmJSModule(const JS::WasmModule* module) {
    294  MOZ_ASSERT(!isFunctionFieldCopiedToStencil);
    295 
    296  MOZ_ASSERT(flags_.kind() == FunctionFlags::NormalFunction);
    297 
    298  // Update flags we will use to allocate the JSFunction.
    299  flags_.clearBaseScript();
    300  flags_.setIsExtended();
    301  flags_.setKind(FunctionFlags::AsmJS);
    302 
    303  // The asm.js stencil container should have been initialized in `setUseAsm`
    304  // above.
    305  if (!compilationState_.asmJS->moduleMap.putNew(index(), module)) {
    306    js::ReportOutOfMemory(fc_);
    307    return false;
    308  }
    309  return true;
    310 }
    311 
    312 ModuleSharedContext::ModuleSharedContext(
    313    FrontendContext* fc, const JS::ReadOnlyCompileOptions& options,
    314    ModuleBuilder& builder, SourceExtent extent)
    315    : SuspendableContext(fc, Kind::Module, options, Directives(true), extent,
    316                         /* isGenerator = */ false,
    317                         /* isAsync = */ false),
    318      bindings(nullptr),
    319      builder(builder) {
    320  thisBinding_ = ThisBinding::Module;
    321  setFlag(ImmutableFlags::HasModuleGoal);
    322 }
    323 
    324 ScriptStencil& FunctionBox::functionStencil() const {
    325  return compilationState_.scriptData[funcDataIndex_];
    326 }
    327 
    328 ScriptStencilExtra& FunctionBox::functionExtraStencil() const {
    329  return compilationState_.scriptExtra[funcDataIndex_];
    330 }
    331 
    332 void SharedContext::copyScriptExtraFields(ScriptStencilExtra& scriptExtra) {
    333  MOZ_ASSERT(!isScriptExtraFieldCopiedToStencil);
    334 
    335  scriptExtra.immutableFlags = immutableFlags_;
    336  scriptExtra.extent = extent_;
    337 
    338  isScriptExtraFieldCopiedToStencil = true;
    339 }
    340 
    341 void FunctionBox::finishScriptFlags() {
    342  MOZ_ASSERT(!isScriptExtraFieldCopiedToStencil);
    343 
    344  using ImmutableFlags = ImmutableScriptFlagsEnum;
    345  immutableFlags_.setFlag(ImmutableFlags::HasMappedArgsObj, hasMappedArgsObj());
    346 }
    347 
    348 void FunctionBox::copyFunctionFields(ScriptStencil& script) {
    349  MOZ_ASSERT(&script == &functionStencil());
    350  MOZ_ASSERT(!isFunctionFieldCopiedToStencil);
    351 
    352  if (atom_) {
    353    compilationState_.parserAtoms.markUsedByStencil(atom_,
    354                                                    ParserAtom::Atomize::Yes);
    355    script.functionAtom = atom_;
    356  }
    357  script.functionFlags = flags_;
    358  if (enclosingScopeIndex_) {
    359    script.setLazyFunctionEnclosingScopeIndex(*enclosingScopeIndex_);
    360  }
    361  if (wasEmittedByEnclosingScript_) {
    362    script.setWasEmittedByEnclosingScript();
    363  }
    364 
    365  isFunctionFieldCopiedToStencil = true;
    366 }
    367 
    368 void FunctionBox::copyFunctionExtraFields(ScriptStencilExtra& scriptExtra) {
    369  if (useMemberInitializers()) {
    370    scriptExtra.setMemberInitializers(memberInitializers());
    371  }
    372 
    373  scriptExtra.nargs = nargs_;
    374 }
    375 
    376 void FunctionBox::copyUpdatedImmutableFlags() {
    377  if (isInitialCompilation) {
    378    ScriptStencilExtra& scriptExtra = functionExtraStencil();
    379    scriptExtra.immutableFlags = immutableFlags_;
    380  }
    381 }
    382 
    383 void FunctionBox::copyUpdatedExtent() {
    384  ScriptStencilExtra& scriptExtra = functionExtraStencil();
    385  scriptExtra.extent = extent_;
    386 }
    387 
    388 void FunctionBox::copyUpdatedMemberInitializers() {
    389  MOZ_ASSERT(useMemberInitializers());
    390  if (isInitialCompilation) {
    391    ScriptStencilExtra& scriptExtra = functionExtraStencil();
    392    scriptExtra.setMemberInitializers(memberInitializers());
    393  } else {
    394    // We are delazifying and the original PrivateScriptData has the member
    395    // initializer information already. See: JSScript::fullyInitFromStencil.
    396  }
    397 }
    398 
    399 void FunctionBox::copyUpdatedEnclosingScopeIndex() {
    400  ScriptStencil& script = functionStencil();
    401  if (enclosingScopeIndex_) {
    402    script.setLazyFunctionEnclosingScopeIndex(*enclosingScopeIndex_);
    403  }
    404 }
    405 
    406 void FunctionBox::copyUpdatedAtomAndFlags() {
    407  ScriptStencil& script = functionStencil();
    408  if (atom_) {
    409    compilationState_.parserAtoms.markUsedByStencil(atom_,
    410                                                    ParserAtom::Atomize::Yes);
    411    script.functionAtom = atom_;
    412  }
    413  script.functionFlags = flags_;
    414 }
    415 
    416 void FunctionBox::copyUpdatedWasEmitted() {
    417  ScriptStencil& script = functionStencil();
    418  if (wasEmittedByEnclosingScript_) {
    419    script.setWasEmittedByEnclosingScript();
    420  }
    421 }
    422 
    423 }  // namespace frontend
    424 }  // namespace js