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/Maybe.h" 11 #include "mozilla/Utf8.h" // mozilla::Utf8Unit 12 13 #include "NamespaceImports.h" 14 15 #include "js/BinASTFormat.h" // JS::BinASTFormat 16 #include "js/CompileOptions.h" 17 #include "js/SourceText.h" 18 #include "vm/Scope.h" 19 #include "vm/TraceLogging.h" 20 21 /* 22 * Structure of all of the support classes. 23 * 24 * Parser: described in Parser.h. 25 * 26 * BytecodeCompiler.cpp: BytecodeCompiler.h *and* BytecodeCompilation.h. 27 * This is the "driver", the high-level operations like "compile this source to 28 * bytecode". It calls the parser, bytecode emitter, etc. 29 * 30 * ParseContext.h and SharedContext.h: Both have similar purposes. They're split 31 * because ParseContext contains information used only by the parser, and 32 * SharedContext contains information used by both the parser and 33 * BytecodeEmitter. 34 * 35 * SharedContext.h: class Directives: this contains boolean flags for tracking 36 * if we're in asm.js or "use strict" code. The "use strict" bit is stored in 37 * SharedContext, and additionally, the full Directives class is stored in 38 * ParseContext - if a direcive is encountered while parsing, this is updated, 39 * and checked in GeneralParser::functionDefinition, and if it changed, the 40 * whole function is re-parsed with the new flags. 41 * 42 * SharedContext.h: abstract class SharedContext: This class contains two 43 * different groups of flags: 44 * 45 * Parse context information. This is information conceptually "passed down" 46 * into parsing sub-nodes. This is like "are we parsing strict code?", and so 47 * the parser can make decisions of how to parse based off that. 48 * 49 * Gathered-while-parsing information. This is information conceptually 50 * "returned up" from parsing sub-nodes. This is like "did we see a use strict 51 * directive"? 52 * 53 * Additionally, subclasses (GlobalSharedContext, ModuleSharedContext, 54 * EvalSharedContext, and FunctionBox) contain binding information, scope 55 * information, and other such bits of data. 56 * 57 * ParseContext.h: class UsedNameTracker: Track which bindings are used in which 58 * scopes. This helps determine which bindings are closed-over, which affects 59 * how they're stored; and whether special bindings like `this` and `arguments` 60 * can be optimized away. 61 * 62 * ParseContext.h: class ParseContext: Extremely complex class that serves a lot 63 * of purposes, but it's a single class - essentially no derived classes - so 64 * it's a little easier to comprehend all at once. (SourceParseContext and 65 * BinASTParseContext do derive from ParseContext, but they do nothing except 66 * adjust the constructor's arguments). 67 * Note it uses a thing called Nestable, which implements a stack of objects: 68 * you can push (and pop) instances to a stack (linked list) as you parse 69 * further into the parse tree. You may push to this stack via calling the 70 * constructor with a GeneralParser as an argument (usually `this`), which 71 * pushes itself onto `this->pc` (so it does get assigned/pushed, even though no 72 * assignment ever appears directly in the parser) 73 * 74 * ParseContext contains a pointer to a SharedContext. 75 * 76 * There's a decent chunk of flags/data collection in here too, some "pass-down" 77 * data and some "return-up" data. 78 * 79 * ParseContext also contains a significant number of *sub*-Nestables as fields 80 * of itself (nestables inside nestables). Note you also push/pop to these via 81 * passing `Parser->pc`, which the constructor of the sub-nestable knows which 82 * ParseContext field to push to. The sub-nestables are: 83 * 84 * ParseContext::Statement: stack of statements. 85 * `if (x) { while (true) { try { ..stack of [if, while, try].. } ... } }` 86 * 87 * ParseContext::LabelStatement: interspersed in Statement stack, for labeled 88 * statements, for e.g. `label: while (true) { break label; }` 89 * 90 * ParseContext::ClassStatement: interspersed in Statement stack, for classes 91 * the parser is currently inside of. 92 * 93 * ParseContext::Scope: Set of variables in each scope (stack of sets): 94 * `{ let a; let b; { let c; } }` 95 * (this gets complicated with `var`, etc., check the class for docs) 96 */ 97 98 class JSLinearString; 99 100 namespace js { 101 102 class ModuleObject; 103 class ScriptSourceObject; 104 105 namespace frontend { 106 107 class ErrorReporter; 108 class FunctionBox; 109 class ParseNode; 110 111 #if defined(JS_BUILD_BINAST) 112 113 JSScript* CompileGlobalBinASTScript( 114 JSContext* cx, const JS::ReadOnlyCompileOptions& options, 115 const uint8_t* src, size_t len, JS::BinASTFormat format, 116 ScriptSourceObject** sourceObjectOut = nullptr); 117 118 MOZ_MUST_USE bool CompileLazyBinASTFunction(JSContext* cx, 119 Handle<BaseScript*> lazy, 120 const uint8_t* buf, size_t length); 121 122 #endif // JS_BUILD_BINAST 123 124 // Compile a module of the given source using the given options. 125 ModuleObject* CompileModule(JSContext* cx, 126 const JS::ReadOnlyCompileOptions& options, 127 JS::SourceText<char16_t>& srcBuf); 128 ModuleObject* CompileModule(JSContext* cx, 129 const JS::ReadOnlyCompileOptions& options, 130 JS::SourceText<mozilla::Utf8Unit>& srcBuf); 131 132 // Parse a module of the given source. This is an internal API; if you want to 133 // compile a module as a user, use CompileModule above. 134 ModuleObject* ParseModule(JSContext* cx, 135 const JS::ReadOnlyCompileOptions& options, 136 JS::SourceText<char16_t>& srcBuf, 137 ScriptSourceObject** sourceObjectOut); 138 ModuleObject* ParseModule(JSContext* cx, 139 const JS::ReadOnlyCompileOptions& options, 140 JS::SourceText<mozilla::Utf8Unit>& srcBuf, 141 ScriptSourceObject** sourceObjectOut); 142 143 // 144 // Compile a single function. The source in srcBuf must match the ECMA-262 145 // FunctionExpression production. 146 // 147 // If nonzero, parameterListEnd is the offset within srcBuf where the parameter 148 // list is expected to end. During parsing, if we find that it ends anywhere 149 // else, it's a SyntaxError. This is used to implement the Function constructor; 150 // it's how we detect that these weird cases are SyntaxErrors: 151 // 152 // Function("/*", "*/x) {") 153 // Function("x){ if (3", "return x;}") 154 // 155 MOZ_MUST_USE bool CompileStandaloneFunction( 156 JSContext* cx, MutableHandleFunction fun, 157 const JS::ReadOnlyCompileOptions& options, JS::SourceText<char16_t>& srcBuf, 158 const mozilla::Maybe<uint32_t>& parameterListEnd, 159 HandleScope enclosingScope = nullptr); 160 161 MOZ_MUST_USE bool CompileStandaloneGenerator( 162 JSContext* cx, MutableHandleFunction fun, 163 const JS::ReadOnlyCompileOptions& options, JS::SourceText<char16_t>& srcBuf, 164 const mozilla::Maybe<uint32_t>& parameterListEnd); 165 166 MOZ_MUST_USE bool CompileStandaloneAsyncFunction( 167 JSContext* cx, MutableHandleFunction fun, 168 const JS::ReadOnlyCompileOptions& options, JS::SourceText<char16_t>& srcBuf, 169 const mozilla::Maybe<uint32_t>& parameterListEnd); 170 171 MOZ_MUST_USE bool CompileStandaloneAsyncGenerator( 172 JSContext* cx, MutableHandleFunction fun, 173 const JS::ReadOnlyCompileOptions& options, JS::SourceText<char16_t>& srcBuf, 174 const mozilla::Maybe<uint32_t>& parameterListEnd); 175 176 ScriptSourceObject* CreateScriptSourceObject( 177 JSContext* cx, const JS::ReadOnlyCompileOptions& options); 178 179 /* 180 * True if str consists of an IdentifierStart character, followed by one or 181 * more IdentifierPart characters, i.e. it matches the IdentifierName production 182 * in the language spec. 183 * 184 * This returns true even if str is a keyword like "if". 185 * 186 * Defined in TokenStream.cpp. 187 */ 188 bool IsIdentifier(JSLinearString* str); 189 190 bool IsIdentifierNameOrPrivateName(JSLinearString* str); 191 192 /* 193 * As above, but taking chars + length. 194 */ 195 bool IsIdentifier(const Latin1Char* chars, size_t length); 196 bool IsIdentifier(const char16_t* chars, size_t length); 197 198 bool IsIdentifierNameOrPrivateName(const Latin1Char* chars, size_t length); 199 bool IsIdentifierNameOrPrivateName(const char16_t* chars, size_t length); 200 201 /* True if str is a keyword. Defined in TokenStream.cpp. */ 202 bool IsKeyword(JSLinearString* str); 203 204 class MOZ_STACK_CLASS AutoFrontendTraceLog { 205 #ifdef JS_TRACE_LOGGING 206 TraceLoggerThread* logger_; 207 mozilla::Maybe<TraceLoggerEvent> frontendEvent_; 208 mozilla::Maybe<AutoTraceLog> frontendLog_; 209 mozilla::Maybe<AutoTraceLog> typeLog_; 210 #endif 211 212 public: 213 AutoFrontendTraceLog(JSContext* cx, const TraceLoggerTextId id, 214 const ErrorReporter& reporter); 215 216 AutoFrontendTraceLog(JSContext* cx, const TraceLoggerTextId id, 217 const ErrorReporter& reporter, FunctionBox* funbox); 218 219 AutoFrontendTraceLog(JSContext* cx, const TraceLoggerTextId id, 220 const ErrorReporter& reporter, ParseNode* pn); 221 }; 222 223 } /* namespace frontend */ 224 } /* namespace js */ 225 226 #endif /* frontend_BytecodeCompiler_h */ 227