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