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 */