Coverage Report

Created: 2025-09-04 06:34

/src/hermes/lib/IRGen/ESTreeIRGen-func.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) Meta Platforms, Inc. and affiliates.
3
 *
4
 * This source code is licensed under the MIT license found in the
5
 * LICENSE file in the root directory of this source tree.
6
 */
7
8
#include "ESTreeIRGen.h"
9
10
#include "llvh/ADT/SmallString.h"
11
12
#include <variant>
13
14
namespace hermes {
15
namespace irgen {
16
17
//===----------------------------------------------------------------------===//
18
// FunctionContext
19
20
FunctionContext::FunctionContext(
21
    ESTreeIRGen *irGen,
22
    Function *function,
23
    sem::FunctionInfo *semInfo)
24
1.33k
    : irGen_(irGen),
25
1.33k
      semInfo_(semInfo),
26
1.33k
      oldContext_(irGen->functionContext_),
27
1.33k
      builderSaveState_(irGen->Builder),
28
1.33k
      function(function),
29
1.33k
      anonymousIDs_(function->getContext().getStringTable()),
30
1.33k
      enterFunctionScope(this) {
31
1.33k
  setupFunctionScope(&enterFunctionScope);
32
1.33k
  irGen->functionContext_ = this;
33
1.33k
  irGen->currentIRScopeDesc_ = function->getFunctionScopeDesc();
34
35
  // Temporarily set the current IR scope to nullptr. IRGen should materialize
36
  // currentIRScopeDesc_ before trying to access it.
37
1.33k
  irGen->currentIRScope_ = nullptr;
38
39
  // Initialize it to LiteralUndefined by default to avoid corner cases.
40
1.33k
  this->capturedNewTarget = irGen->Builder.getLiteralUndefined();
41
42
1.33k
  if (semInfo_) {
43
    // Allocate the label table. Each label definition will be encountered in
44
    // the AST before it is referenced (because of the nature of JavaScript), at
45
    // which point we will initialize the GotoLabel structure with basic blocks
46
    // targets.
47
1.33k
    labels_.resize(semInfo_->labelCount);
48
1.33k
  }
49
1.33k
}
50
51
1.33k
void FunctionContext::setupFunctionScope(EnterBlockScope *scope) {
52
1.33k
  functionScope = &scope->blockScope_;
53
1.33k
  blockScope = functionScope;
54
1.33k
}
55
56
1.33k
FunctionContext::~FunctionContext() {
57
1.33k
  irGen_->functionContext_ = oldContext_;
58
1.33k
  irGen_->Builder.setCurrentSourceLevelScope(irGen_->currentIRScopeDesc_);
59
1.33k
}
60
61
1.72k
Identifier FunctionContext::genAnonymousLabelName(llvh::StringRef hint) {
62
1.72k
  return anonymousIDs_.next(hint);
63
1.72k
}
64
65
//===----------------------------------------------------------------------===//
66
// EnterBlockScope
67
EnterBlockScope::EnterBlockScope(FunctionContext *currentContext)
68
1.33k
    : currentContext_(currentContext),
69
1.33k
      oldIRScopeDesc_(currentContext->irGen_->currentIRScopeDesc_),
70
1.33k
      oldIRScope_(currentContext->irGen_->currentIRScope_),
71
1.33k
      oldBlockScope_(currentContext->blockScope),
72
1.33k
      blockScope_(currentContext->irGen_->nameTable_) {
73
1.33k
  currentContext->blockScope = &blockScope_;
74
1.33k
}
75
76
1.33k
EnterBlockScope::~EnterBlockScope() {
77
1.33k
  ESTreeIRGen *irgen = currentContext_->irGen_;
78
1.33k
  currentContext_->blockScope = oldBlockScope_;
79
1.33k
  irgen->currentIRScope_ = oldIRScope_;
80
1.33k
  irgen->currentIRScopeDesc_ = oldIRScopeDesc_;
81
1.33k
  irgen->Builder.setCurrentSourceLevelScope(irgen->currentIRScopeDesc_);
82
1.33k
}
83
84
//===----------------------------------------------------------------------===//
85
// ESTreeIRGen
86
87
void ESTreeIRGen::genFunctionDeclaration(
88
0
    ESTree::FunctionDeclarationNode *func) {
89
  // Find the name of the function.
90
0
  Identifier functionName = getNameFieldFromID(func->_id);
91
0
  LLVM_DEBUG(llvh::dbgs() << "IRGen function \"" << functionName << "\".\n");
92
93
0
  Function *newFunc = func->_async
94
0
      ? genAsyncFunction(functionName, nullptr, func)
95
0
      : func->_generator ? genGeneratorFunction(functionName, nullptr, func)
96
0
                         : genES5Function(functionName, nullptr, func);
97
98
0
  functionForDecl[func] = {newFunc, AlreadyEmitted::No};
99
0
}
100
101
0
void ESTreeIRGen::emitCreateFunction(ESTree::FunctionDeclarationNode *func) {
102
0
  Identifier functionName = getNameFieldFromID(func->_id);
103
104
0
  auto it = functionForDecl.find(func);
105
0
  assert(it != functionForDecl.end() && "all inner functions should be known");
106
107
0
  if (it->second.second == AlreadyEmitted::Yes) {
108
0
    return;
109
0
  }
110
111
0
  it->second.second = AlreadyEmitted::Yes;
112
113
0
  auto *funcStorage = nameTable_.lookup(functionName);
114
0
  assert(
115
0
      funcStorage && "function declaration variable should have been hoisted");
116
117
  // Store the newly created closure into a frame variable with the same name.
118
0
  auto *newClosure =
119
0
      Builder.createCreateFunctionInst(it->second.first, currentIRScope_);
120
121
0
  emitStore(newClosure, funcStorage, true);
122
0
}
123
124
1.37k
void ESTreeIRGen::hoistCreateFunctions(ESTree::Node *containingNode) {
125
1.37k
  const auto &closures = curFunction()->getSemInfo()->closures;
126
1.37k
  auto it = closures.find(containingNode);
127
1.37k
  if (it == closures.end()) {
128
0
    return;
129
0
  }
130
131
1.37k
  for (ESTree::FunctionDeclarationNode *funcDecl : *it->second) {
132
0
    emitCreateFunction(funcDecl);
133
0
  }
134
1.37k
}
135
136
Value *ESTreeIRGen::genFunctionExpression(
137
    ESTree::FunctionExpressionNode *FE,
138
6
    Identifier nameHint) {
139
6
  LLVM_DEBUG(
140
6
      llvh::dbgs()
141
6
      << "Creating anonymous closure. "
142
6
      << Builder.getInsertionBlock()->getParent()->getInternalName() << ".\n");
143
144
6
  std::variant<std::monostate, NameTableScopeTy, EnterBlockScope> newScope;
145
146
6
  if (!Mod->getContext().getCodeGenerationSettings().enableBlockScoping) {
147
6
    newScope.emplace<NameTableScopeTy>(nameTable_);
148
6
  } else {
149
0
    newScope.emplace<EnterBlockScope>(curFunction());
150
0
    newDeclarativeEnvironment();
151
0
  }
152
6
  Variable *tempClosureVar = nullptr;
153
154
6
  Identifier originalNameIden = nameHint;
155
6
  if (FE->_id) {
156
0
    if (!Mod->getContext().getCodeGenerationSettings().enableBlockScoping) {
157
0
      auto closureName = genAnonymousLabelName("closure");
158
0
      tempClosureVar = Builder.createVariable(
159
0
          curFunction()->function->getFunctionScopeDesc(),
160
0
          Variable::DeclKind::Var,
161
0
          closureName);
162
163
      // Insert the synthesized variable into the name table, so it can be
164
      // looked up internally as well.
165
0
      nameTable_.insertIntoScope(
166
0
          curFunction()->functionScope,
167
0
          tempClosureVar->getName(),
168
0
          tempClosureVar);
169
170
      // Alias the lexical name to the synthesized variable.
171
0
      originalNameIden = getNameFieldFromID(FE->_id);
172
0
      nameTable_.insert(originalNameIden, tempClosureVar);
173
0
    } else {
174
      // Use the expression's ID for its closure name, as well as its variable
175
      // name -- which is OK because we're in a new scope.
176
0
      originalNameIden = getNameFieldFromID(FE->_id);
177
178
0
      auto closureName = genAnonymousLabelName(originalNameIden.str());
179
0
      tempClosureVar = Builder.createVariable(
180
0
          currentIRScopeDesc_, Variable::DeclKind::Const, closureName);
181
182
      // ES2023 dictates that function expression's ID are non-strict immutable
183
      // bindings.
184
0
      tempClosureVar->setStrictImmutableBinding(false);
185
186
0
      nameTable_.insertIntoScope(
187
0
          curFunction()->blockScope, originalNameIden, tempClosureVar);
188
0
    }
189
0
  }
190
191
6
  Function *newFunc = FE->_async
192
6
      ? genAsyncFunction(originalNameIden, tempClosureVar, FE)
193
6
      : FE->_generator
194
6
      ? genGeneratorFunction(originalNameIden, tempClosureVar, FE)
195
6
      : genES5Function(originalNameIden, tempClosureVar, FE);
196
197
6
  Value *closure = Builder.createCreateFunctionInst(newFunc, currentIRScope_);
198
199
6
  if (tempClosureVar)
200
0
    emitStore(closure, tempClosureVar, true);
201
202
6
  return closure;
203
6
}
204
205
Value *ESTreeIRGen::genArrowFunctionExpression(
206
    ESTree::ArrowFunctionExpressionNode *AF,
207
1.30k
    Identifier nameHint) {
208
1.30k
  LLVM_DEBUG(
209
1.30k
      llvh::dbgs()
210
1.30k
      << "Creating arrow function. "
211
1.30k
      << Builder.getInsertionBlock()->getParent()->getInternalName() << ".\n");
212
213
1.30k
  if (AF->_async) {
214
0
    Builder.getModule()->getContext().getSourceErrorManager().error(
215
0
        AF->getSourceRange(), Twine("async functions are unsupported"));
216
0
    return Builder.getLiteralUndefined();
217
0
  }
218
219
1.30k
  auto *newFunc = Builder.createFunction(
220
1.30k
      newScopeDesc(),
221
1.30k
      genAnonymousFunctionNameIfNeeded(nameHint),
222
1.30k
      Function::DefinitionKind::ES6Arrow,
223
1.30k
      ESTree::isStrict(AF->strictness),
224
1.30k
      AF->sourceVisibility,
225
1.30k
      AF->getSourceRange());
226
227
1.30k
  {
228
1.30k
    FunctionContext newFunctionContext{this, newFunc, AF->getSemInfo()};
229
230
    // Propagate captured "this", "new.target" and "arguments" from parents.
231
1.30k
    auto *prev = curFunction()->getPreviousContext();
232
1.30k
    curFunction()->capturedThis = prev->capturedThis;
233
1.30k
    curFunction()->capturedNewTarget = prev->capturedNewTarget;
234
1.30k
    curFunction()->capturedArguments = prev->capturedArguments;
235
236
1.30k
    emitFunctionPreamble(Builder.createBasicBlock(newFunc));
237
1.30k
    emitTopLevelDeclarations(AF, AF->_body, DoEmitParameters::YesMultiScopes);
238
239
1.30k
    genFunctionBody(AF->_body);
240
1.30k
    emitFunctionEpilogue(Builder.getLiteralUndefined());
241
1.30k
  }
242
243
  // Emit CreateFunctionInst after we have restored the builder state.
244
1.30k
  return Builder.createCreateFunctionInst(newFunc, currentIRScope_);
245
1.30k
}
246
247
namespace {
248
6
ESTree::NodeKind getLazyFunctionKind(ESTree::FunctionLikeNode *node) {
249
6
  if (node->isMethodDefinition) {
250
    // This is not a regular function expression but getter/setter.
251
    // If we want to reparse it later, we have to start from an
252
    // identifier and not from a 'function' keyword.
253
0
    return ESTree::NodeKind::Property;
254
0
  }
255
6
  return node->getKind();
256
6
}
257
} // namespace
258
Function *ESTreeIRGen::genES5Function(
259
    Identifier originalName,
260
    Variable *lazyClosureAlias,
261
    ESTree::FunctionLikeNode *functionNode,
262
6
    bool isGeneratorInnerFunction) {
263
6
  assert(functionNode && "Function AST cannot be null");
264
265
6
  auto *body = ESTree::getBlockStatement(functionNode);
266
6
  assert(body && "body of ES5 function cannot be null");
267
268
6
  Function *newFunction = isGeneratorInnerFunction
269
6
      ? Builder.createGeneratorInnerFunction(
270
0
            newScopeDesc(),
271
0
            genAnonymousFunctionNameIfNeeded(originalName),
272
0
            Function::DefinitionKind::ES5Function,
273
0
            ESTree::isStrict(functionNode->strictness),
274
0
            functionNode->getSourceRange(),
275
0
            /* insertBefore */ nullptr)
276
6
      : Builder.createFunction(
277
6
            newScopeDesc(),
278
6
            genAnonymousFunctionNameIfNeeded(originalName),
279
6
            Function::DefinitionKind::ES5Function,
280
6
            ESTree::isStrict(functionNode->strictness),
281
6
            functionNode->sourceVisibility,
282
6
            functionNode->getSourceRange(),
283
6
            /* isGlobal */ false,
284
6
            /* insertBefore */ nullptr);
285
286
6
  newFunction->setLazyClosureAlias(lazyClosureAlias);
287
288
6
  if (auto *bodyBlock = llvh::dyn_cast<ESTree::BlockStatementNode>(body)) {
289
6
    if (bodyBlock->isLazyFunctionBody) {
290
6
      assert(
291
6
          !isGeneratorInnerFunction &&
292
6
          "generator inner function should be included with outer function");
293
6
      setupLazyScope(functionNode, newFunction, body);
294
6
      return newFunction;
295
6
    }
296
6
  }
297
298
0
  FunctionContext newFunctionContext{
299
0
      this, newFunction, functionNode->getSemInfo()};
300
301
0
  if (isGeneratorInnerFunction) {
302
    // StartGeneratorInst
303
    // ResumeGeneratorInst
304
    // at the beginning of the function, to allow for the first .next() call.
305
0
    auto *initGenBB = Builder.createBasicBlock(newFunction);
306
0
    Builder.setInsertionBlock(initGenBB);
307
0
    Builder.createStartGeneratorInst();
308
0
    auto *prologueBB = Builder.createBasicBlock(newFunction);
309
0
    auto *prologueResumeIsReturn = Builder.createAllocStackInst(
310
0
        genAnonymousLabelName("isReturn_prologue"));
311
0
    genResumeGenerator(GenFinally::No, prologueResumeIsReturn, prologueBB);
312
313
0
    if (hasSimpleParams(functionNode)) {
314
      // If there are simple params, then we don't need an extra yield/resume.
315
      // They can simply be initialized on the first call to `.next`.
316
0
      Builder.setInsertionBlock(prologueBB);
317
0
      emitFunctionPreamble(prologueBB);
318
0
      initCaptureStateInES5Function();
319
0
      emitTopLevelDeclarations(
320
0
          functionNode, body, DoEmitParameters::YesMultiScopes);
321
0
    } else {
322
      // If there are non-simple params, then we must add a new yield/resume.
323
      // The `.next()` call will occur once in the outer function, before
324
      // the iterator is returned to the caller of the `function*`.
325
0
      auto *entryPointBB = Builder.createBasicBlock(newFunction);
326
0
      auto *entryPointResumeIsReturn =
327
0
          Builder.createAllocStackInst(genAnonymousLabelName("isReturn_entry"));
328
329
      // Initialize parameters.
330
0
      Builder.setInsertionBlock(prologueBB);
331
0
      emitFunctionPreamble(prologueBB);
332
0
      initCaptureStateInES5Function();
333
0
      emitTopLevelDeclarations(
334
0
          functionNode, body, DoEmitParameters::YesMultiScopes);
335
0
      Builder.createSaveAndYieldInst(
336
0
          Builder.getLiteralUndefined(), entryPointBB);
337
338
      // Actual entry point of function from the caller's perspective.
339
0
      Builder.setInsertionBlock(entryPointBB);
340
0
      genResumeGenerator(
341
0
          GenFinally::No,
342
0
          entryPointResumeIsReturn,
343
0
          Builder.createBasicBlock(newFunction));
344
0
    }
345
0
  } else {
346
0
    emitFunctionPreamble(Builder.createBasicBlock(newFunction));
347
0
    initCaptureStateInES5Function();
348
0
    emitTopLevelDeclarations(
349
0
        functionNode, body, DoEmitParameters::YesMultiScopes);
350
0
  }
351
352
0
  genFunctionBody(body);
353
0
  emitFunctionEpilogue(Builder.getLiteralUndefined());
354
355
0
  return curFunction()->function;
356
6
}
357
358
Function *ESTreeIRGen::genGeneratorFunction(
359
    Identifier originalName,
360
    Variable *lazyClosureAlias,
361
0
    ESTree::FunctionLikeNode *functionNode) {
362
0
  assert(functionNode && "Function AST cannot be null");
363
364
0
  if (!Builder.getModule()->getContext().isGeneratorEnabled()) {
365
0
    Builder.getModule()->getContext().getSourceErrorManager().error(
366
0
        functionNode->getSourceRange(), "generator compilation is disabled");
367
0
  }
368
369
  // Build the outer function which creates the generator.
370
  // Does not have an associated source range.
371
0
  auto *outerFn = Builder.createGeneratorFunction(
372
0
      newScopeDesc(),
373
0
      genAnonymousFunctionNameIfNeeded(originalName),
374
0
      Function::DefinitionKind::ES5Function,
375
0
      ESTree::isStrict(functionNode->strictness),
376
0
      functionNode->sourceVisibility,
377
0
      functionNode->getSourceRange(),
378
0
      /* insertBefore */ nullptr);
379
0
  outerFn->setLazyClosureAlias(lazyClosureAlias);
380
381
0
  auto *body = ESTree::getBlockStatement(functionNode);
382
0
  if (auto *bodyBlock = llvh::dyn_cast<ESTree::BlockStatementNode>(body)) {
383
0
    if (bodyBlock->isLazyFunctionBody) {
384
0
      setupLazyScope(functionNode, outerFn, body);
385
0
      return outerFn;
386
0
    }
387
0
  }
388
389
0
  {
390
0
    FunctionContext outerFnContext{this, outerFn, functionNode->getSemInfo()};
391
392
    // Build the inner function. This must be done in the outerFnContext
393
    // since it's lexically considered a child function.
394
0
    auto *innerFn = genES5Function(
395
0
        genAnonymousLabelName(originalName.isValid() ? originalName.str() : ""),
396
0
        nullptr,
397
0
        functionNode,
398
0
        true);
399
400
0
    emitFunctionPreamble(Builder.createBasicBlock(outerFn));
401
0
    initCaptureStateInES5Function();
402
0
    emitTopLevelDeclarations(
403
0
        functionNode,
404
0
        ESTree::getBlockStatement(functionNode),
405
0
        DoEmitParameters::No);
406
407
    // Create a generator function, which will store the arguments.
408
0
    auto *gen = Builder.createCreateGeneratorInst(innerFn, currentIRScope_);
409
410
0
    if (!hasSimpleParams(functionNode)) {
411
      // If there are non-simple params, step the inner function once to
412
      // initialize them.
413
0
      Value *next = Builder.createLoadPropertyInst(gen, "next");
414
0
      Builder.createCallInst(CallInst::kNoTextifiedCallee, next, gen, {});
415
0
    }
416
417
0
    emitFunctionEpilogue(gen);
418
0
  }
419
420
0
  return outerFn;
421
0
}
422
423
void ESTreeIRGen::setupLazyScope(
424
    ESTree::FunctionLikeNode *functionNode,
425
    Function *function,
426
6
    ESTree::BlockStatementNode *bodyBlock) {
427
6
  assert(
428
6
      bodyBlock->isLazyFunctionBody &&
429
6
      "setupLazyScope can only be used with lazy function bodies");
430
  // Set the AST position and variable context so we can continue later.
431
  // Save the scope chain starting from function's parent (i.e., the last
432
  // materialized scope).
433
6
  function->setLazyScope(
434
6
      saveScopeChain(function->getFunctionScopeDesc()->getParent()));
435
6
  auto &lazySource = function->getLazySource();
436
6
  lazySource.bufferId = bodyBlock->bufferId;
437
6
  lazySource.nodeKind = getLazyFunctionKind(functionNode);
438
6
  lazySource.functionRange = functionNode->getSourceRange();
439
6
  lazySource.paramYield = bodyBlock->paramYield;
440
6
  lazySource.paramAwait = bodyBlock->paramAwait;
441
442
  // Set the function's .length.
443
6
  function->setExpectedParamCountIncludingThis(
444
6
      countExpectedArgumentsIncludingThis(functionNode));
445
6
}
446
447
Function *ESTreeIRGen::genAsyncFunction(
448
    Identifier originalName,
449
    Variable *lazyClosureAlias,
450
0
    ESTree::FunctionLikeNode *functionNode) {
451
0
  assert(functionNode && "Function AST cannot be null");
452
453
0
  if (!Builder.getModule()->getContext().isGeneratorEnabled()) {
454
0
    Builder.getModule()->getContext().getSourceErrorManager().error(
455
0
        functionNode->getSourceRange(),
456
0
        "async function compilation requires enabling generator");
457
0
  }
458
459
0
  auto *asyncFn = Builder.createAsyncFunction(
460
0
      newScopeDesc(),
461
0
      genAnonymousFunctionNameIfNeeded(originalName),
462
0
      Function::DefinitionKind::ES5Function,
463
0
      ESTree::isStrict(functionNode->strictness),
464
0
      functionNode->sourceVisibility,
465
0
      functionNode->getSourceRange(),
466
0
      /* insertBefore */ nullptr);
467
468
  // Setup lazy compilation
469
0
  asyncFn->setLazyClosureAlias(lazyClosureAlias);
470
471
0
  auto *body = ESTree::getBlockStatement(functionNode);
472
0
  if (auto *bodyBlock = llvh::dyn_cast<ESTree::BlockStatementNode>(body)) {
473
0
    if (bodyBlock->isLazyFunctionBody) {
474
0
      setupLazyScope(functionNode, asyncFn, body);
475
0
      return asyncFn;
476
0
    }
477
0
  }
478
479
0
  {
480
0
    FunctionContext asyncFnContext{this, asyncFn, functionNode->getSemInfo()};
481
482
    // Build the inner generator. This must be done in the outerFnContext
483
    // since it's lexically considered a child function.
484
0
    auto *gen = genGeneratorFunction(
485
0
        genAnonymousLabelName(originalName.isValid() ? originalName.str() : ""),
486
0
        lazyClosureAlias,
487
0
        functionNode);
488
489
    // The outer async function need not emit code for parameters.
490
    // It would simply delegate `arguments` object down to inner generator.
491
    // This avoid emitting code e.g. destructuring parameters twice.
492
0
    emitFunctionPreamble(Builder.createBasicBlock(asyncFn));
493
0
    initCaptureStateInES5Function();
494
0
    emitTopLevelDeclarations(
495
0
        functionNode,
496
0
        ESTree::getBlockStatement(functionNode),
497
0
        DoEmitParameters::No);
498
499
0
    auto *genClosure = Builder.createCreateFunctionInst(gen, currentIRScope_);
500
0
    auto *thisArg = curFunction()->function->getThisParameter();
501
0
    auto *argumentsList = curFunction()->createArgumentsInst;
502
503
0
    auto *spawnAsyncClosure = Builder.createGetBuiltinClosureInst(
504
0
        BuiltinMethod::HermesBuiltin_spawnAsync);
505
506
0
    auto *res = Builder.createCallInst(
507
0
        CallInst::kNoTextifiedCallee,
508
0
        spawnAsyncClosure,
509
0
        Builder.getLiteralUndefined(),
510
0
        {genClosure, thisArg, argumentsList});
511
512
0
    emitFunctionEpilogue(res);
513
0
  }
514
0
  return asyncFn;
515
0
}
516
517
36
void ESTreeIRGen::initCaptureStateInES5Function() {
518
  // Capture "this", "new.target" and "arguments" if there are inner arrows.
519
36
  if (!curFunction()->getSemInfo()->containsArrowFunctions)
520
31
    return;
521
522
  // "this".
523
5
  curFunction()->capturedThis = Builder.createVariable(
524
5
      currentIRScopeDesc_,
525
5
      Variable::DeclKind::Var,
526
5
      genAnonymousLabelName("this"));
527
5
  emitStore(
528
5
      Builder.getFunction()->getThisParameter(),
529
5
      curFunction()->capturedThis,
530
5
      true);
531
532
  // "new.target".
533
5
  curFunction()->capturedNewTarget = Builder.createVariable(
534
5
      currentIRScopeDesc_,
535
5
      Variable::DeclKind::Var,
536
5
      genAnonymousLabelName("new.target"));
537
5
  emitStore(
538
5
      Builder.createGetNewTargetInst(), curFunction()->capturedNewTarget, true);
539
540
  // "arguments".
541
5
  if (curFunction()->getSemInfo()->containsArrowFunctionsUsingArguments) {
542
0
    curFunction()->capturedArguments = Builder.createVariable(
543
0
        currentIRScopeDesc_,
544
0
        Variable::DeclKind::Var,
545
0
        genAnonymousLabelName("arguments"));
546
0
    emitStore(
547
0
        curFunction()->createArgumentsInst,
548
0
        curFunction()->capturedArguments,
549
0
        true);
550
0
  }
551
5
}
552
553
1.33k
void ESTreeIRGen::emitFunctionPreamble(BasicBlock *entry) {
554
1.33k
  auto *newFunc = curFunction()->function;
555
556
1.33k
  Builder.setLocation(newFunc->getSourceRange().Start);
557
1.33k
  Builder.setCurrentSourceLevelScope(nullptr);
558
559
1.33k
  BasicBlock *realEntry = &newFunc->front();
560
1.33k
  if (realEntry->empty()) {
561
1.33k
    Builder.setInsertionBlock(realEntry);
562
1.33k
  } else {
563
0
    Builder.setInsertionPoint(&realEntry->front());
564
0
  }
565
  // Create the function scope.
566
1.33k
  currentIRScope_ =
567
1.33k
      Builder.createCreateScopeInst(newFunc->getFunctionScopeDesc());
568
569
  // Start pumping instructions into the entry basic block.
570
1.33k
  Builder.setInsertionBlock(entry);
571
1.33k
  Builder.setCurrentSourceLevelScope(newFunc->getFunctionScopeDesc());
572
573
  // Always insert a CreateArgumentsInst. We will delete it later if it is
574
  // unused.
575
1.33k
  curFunction()->createArgumentsInst = Builder.createCreateArgumentsInst();
576
577
  // Always create the "this" parameter. It needs to be created before we
578
  // initialized the ES5 capture state.
579
1.33k
  Builder.createThisParameter(newFunc);
580
1.33k
}
581
582
void ESTreeIRGen::emitTopLevelDeclarations(
583
    ESTree::FunctionLikeNode *funcNode,
584
    ESTree::Node *body,
585
1.33k
    DoEmitParameters doEmitParameters) {
586
  // There is a lot happening in this function w.r.t. function scopes, but that
587
  // can be summarizes as follows:
588
  //
589
  //    topLevelScope = Scope();                                #1
590
  //    currentScope = topLevelScope
591
  //
592
  //    if !isStrict and hasParamExpressions:
593
  //        paramExpressionScope = InnerScope(currentScope)
594
  //        currentScope = paramExpressionScope                 #2
595
  //
596
  //    << emit parameter expressions >>
597
  //
598
  //    if hasParamExpressions:
599
  //       varScope = InnerScope(currentScope)
600
  //       currentScope = varScope                              #3
601
  //
602
  //    << emit var declarations >>
603
  //
604
  //    if !isStrict:
605
  //       lexicalScope = InnerScope(currentScope)              #4
606
  //       currentScope = lexicalScope
607
  //
608
  //    << emit lexical declarations >>
609
  //
610
  // Thus at the end of this method, currentIRScopeDesc_ (i.e., currentScope
611
  // above) should be
612
  //
613
  // 1. !isStrict and !hasParamExpressions:
614
  //        currentIRScopeDesc_ == lexicalScope
615
  //        lexicalScope.parent == topLevelScope
616
  //        paramExpressionScope == null
617
  //        varScope == null
618
  // 2. !isStrict and hasParamExpressions:
619
  //        currentIRScopeDesc_ == lexicalScope
620
  //        lexicalScope.parent == varScope
621
  //        varScope.parent == paramExpressionScope
622
  //        paramExpressionScope.parent == topLevelScope
623
  // 3. isStrict and !hasParamExpressions:
624
  //        currentIRScopeDesc_ == topLevelScope
625
  //        paramExpressionScope == null
626
  //        varScope == null
627
  //        lexicalScope == null
628
  // 4. isStrict and hasParamExpressions:
629
  //        currentIRScopeDesc_ == varScope
630
  //        varScope.parent == topLevelScope
631
  //        paramExpressionScope == null
632
  //        lexicalScope == null
633
  //
634
  // The following variables are used to assert those conditions.
635
1.33k
  ScopeDesc *topLevelScope = currentIRScopeDesc_;
636
1.33k
  ScopeDesc *paramExpressionScope{};
637
1.33k
  ScopeDesc *varScope{};
638
1.33k
  ScopeDesc *lexicalScope{};
639
640
1.33k
  if (!Mod->getContext().getCodeGenerationSettings().enableBlockScoping) {
641
1.33k
    if (doEmitParameters == DoEmitParameters::YesMultiScopes) {
642
      // Block scoping is disabled, so there's no point in emitting separate
643
      // scopes.
644
1.30k
      doEmitParameters = DoEmitParameters::Yes;
645
1.30k
    }
646
1.33k
  }
647
648
1.33k
  const bool hasParamExpressions = ESTree::hasParamExpressions(funcNode);
649
1.33k
  if (doEmitParameters == DoEmitParameters::YesMultiScopes) {
650
0
    if (!ESTree::isStrict(funcNode->strictness) && hasParamExpressions) {
651
0
      curFunction()->enterOptionalFunctionScope(
652
0
          &FunctionContext::enterParamScope);
653
0
      newDeclarativeEnvironment();
654
0
      paramExpressionScope = currentIRScopeDesc_;
655
0
    }
656
0
  }
657
658
1.33k
  if (doEmitParameters != DoEmitParameters::No) {
659
    // Create function parameters, register them in the scope, and initialize
660
    // them with their income values.
661
1.33k
    emitParameters(funcNode, hasParamExpressions);
662
1.33k
  } else {
663
0
    curFunction()->function->setExpectedParamCountIncludingThis(
664
0
        countExpectedArgumentsIncludingThis(funcNode));
665
0
  }
666
667
1.33k
  auto *semInfo = curFunction()->getSemInfo();
668
1.33k
  if (doEmitParameters != DoEmitParameters::YesMultiScopes ||
669
1.33k
      !hasParamExpressions) {
670
    // Create variable declarations for each of the hoisted variables and
671
    // functions. Initialize them to undefined.
672
1.33k
    for (const sem::FunctionInfo::VarDecl &decl : semInfo->varScoped) {
673
23
      createNewBinding(
674
23
          currentIRScopeDesc_,
675
23
          decl.kind,
676
23
          decl.identifier,
677
23
          decl.needsInitializer);
678
23
    }
679
680
1.33k
  } else {
681
0
    curFunction()->enterOptionalFunctionScope(&FunctionContext::enterVarScope);
682
0
    newDeclarativeEnvironment();
683
0
    varScope = currentIRScopeDesc_;
684
685
0
    for (const sem::FunctionInfo::VarDecl &decl : semInfo->varScoped) {
686
0
      Value *init = nameTable_.lookup(getNameFieldFromID(decl.identifier));
687
0
      if (init) {
688
0
        init = emitLoad(init);
689
0
      }
690
0
      createNewBinding(
691
0
          currentIRScopeDesc_,
692
0
          decl.kind,
693
0
          decl.identifier,
694
0
          decl.needsInitializer,
695
0
          init);
696
0
    }
697
0
  }
698
699
1.33k
  if (doEmitParameters == DoEmitParameters::YesMultiScopes) {
700
0
    if (!ESTree::isStrict(funcNode->strictness)) {
701
0
      curFunction()->enterOptionalFunctionScope(
702
0
          &FunctionContext::enterTopLevelLexicalDeclarationsScope);
703
0
      newDeclarativeEnvironment();
704
0
      lexicalScope = currentIRScopeDesc_;
705
0
    }
706
0
  }
707
708
  // Now that scope creation is completed, ensure that the expectations hold:
709
1.33k
  if (doEmitParameters == DoEmitParameters::YesMultiScopes) {
710
0
    (void)topLevelScope;
711
0
    (void)paramExpressionScope;
712
0
    (void)varScope;
713
0
    (void)lexicalScope;
714
0
    if (!ESTree::isStrict(funcNode->strictness)) {
715
0
      if (!hasParamExpressions) {
716
        // 1. !isStrict and !hasParamExpressions:
717
0
        assert(currentIRScopeDesc_ == lexicalScope);
718
0
        assert(lexicalScope->getParent() == topLevelScope);
719
0
        assert(paramExpressionScope == nullptr);
720
0
        assert(varScope == nullptr);
721
0
      } else {
722
        // 2. !isStrict and hasParamExpressions:
723
0
        assert(currentIRScopeDesc_ == lexicalScope);
724
0
        assert(lexicalScope->getParent() == varScope);
725
0
        assert(varScope->getParent() == paramExpressionScope);
726
0
        assert(paramExpressionScope->getParent() == topLevelScope);
727
0
      }
728
0
    } else {
729
0
      if (!hasParamExpressions) {
730
        // 3. isStrict and !hasParamExpressions:
731
0
        assert(currentIRScopeDesc_ == topLevelScope);
732
0
        assert(paramExpressionScope == nullptr);
733
0
        assert(varScope == nullptr);
734
0
        assert(lexicalScope == nullptr);
735
0
      } else {
736
        // 4. isStrict and hasParamExpressions:
737
0
        assert(currentIRScopeDesc_ == varScope);
738
0
        assert(varScope->getParent() == topLevelScope);
739
0
        assert(paramExpressionScope == nullptr);
740
0
        assert(lexicalScope == nullptr);
741
0
      }
742
0
    }
743
0
  }
744
745
  // Now create variable declarations for each scoped variable/function in body.
746
  // let/const bindings are initialized to empty, and functions to undefined.
747
1.33k
  createScopeBindings(currentIRScopeDesc_, body);
748
749
  // Generate the code for import declarations before generating the rest of the
750
  // body.
751
1.33k
  for (ESTree::ImportDeclarationNode *importDecl : semInfo->imports) {
752
0
    genImportDeclaration(importDecl);
753
0
  }
754
755
  // Generate all closures declared in body. Any hoisted
756
  // functions from inner scopes have already been declared.
757
1.33k
  genFunctionDeclarations(body);
758
759
  // Pre-hoists all functions that are defined within body (but not in
760
  // BlockStatments in it).
761
1.33k
  hoistCreateFunctions(body);
762
1.33k
}
763
764
1.33k
void ESTreeIRGen::genFunctionDeclarations(ESTree::Node *containingNode) {
765
1.33k
  auto *semInfo = curFunction()->getSemInfo();
766
767
1.33k
  auto it = semInfo->closures.find(containingNode);
768
1.33k
  if (it != semInfo->closures.end()) {
769
1.33k
    for (ESTree::FunctionDeclarationNode *fd : *it->second) {
770
0
      genFunctionDeclaration(fd);
771
0
    }
772
1.33k
  }
773
1.33k
}
774
775
void ESTreeIRGen::createScopeBindings(
776
    ScopeDesc *scopeDesc,
777
1.33k
    ESTree::Node *containingNode) {
778
1.33k
  auto *semInfo = curFunction()->getSemInfo();
779
780
1.33k
  auto it = semInfo->lexicallyScoped.find(containingNode);
781
1.33k
  if (it != semInfo->lexicallyScoped.end()) {
782
1.33k
    for (const sem::FunctionInfo::VarDecl &decl : *it->second) {
783
0
      LLVM_DEBUG(
784
0
          llvh::dbgs() << "creating binding " << decl.identifier->_name
785
0
                       << " in scope " << scopeDesc << "\n");
786
0
      createNewBinding(
787
0
          scopeDesc, decl.kind, decl.identifier, decl.needsInitializer);
788
0
      if (Mod->getContext().getCodeGenerationSettings().enableBlockScoping) {
789
0
        if (decl.kind != VarDecl::Kind::Var && scopeDesc->isGlobalScope() &&
790
0
            llvh::isa<ESTree::ProgramNode>(containingNode)) {
791
          // The newly created Variable is a const/let declaration, so the
792
          // running program must check whether it is a valid name. For example,
793
          //
794
          // let undefined;
795
          //
796
          // is an invalid global let declaration because undefined is a
797
          // restricted global name.
798
0
          IRBuilder::ScopedLocationChange slc(
799
0
              Builder, decl.identifier->getSourceRange().Start);
800
0
          Builder.createThrowIfHasRestrictedGlobalPropertyInst(
801
0
              decl.identifier->_name->str());
802
0
        }
803
0
      }
804
0
    }
805
1.33k
  }
806
1.33k
}
807
808
void ESTreeIRGen::createNewBinding(
809
    ScopeDesc *scopeDesc,
810
    VarDecl::Kind kind,
811
    ESTree::Node *id,
812
    bool needsInitializer,
813
23
    Value *init) {
814
23
  Identifier name = getNameFieldFromID(id);
815
23
  auto res = declareVariableOrGlobalProperty(scopeDesc, kind, name);
816
  // If this is not a frame variable or it was already declared, skip.
817
23
  auto *var = llvh::dyn_cast<Variable>(res.first);
818
23
  if (!needsInitializer || !var || !res.second)
819
19
    return;
820
821
4
  if (!init) {
822
4
    init = var->getObeysTDZ() ? (Literal *)Builder.getLiteralEmpty()
823
4
                              : (Literal *)Builder.getLiteralUndefined();
824
4
  }
825
826
  // Otherwise, initialize it to undefined or empty, depending on TDZ.
827
4
  Builder.createStoreFrameInst(init, var, currentIRScope_);
828
4
}
829
830
void ESTreeIRGen::emitParameters(
831
    ESTree::FunctionLikeNode *funcNode,
832
1.33k
    bool hasParamExpressions) {
833
1.33k
  auto *newFunc = curFunction()->function;
834
835
1.33k
  LLVM_DEBUG(llvh::dbgs() << "IRGen function parameters.\n");
836
837
1.33k
  if (!Mod->getContext().getCodeGenerationSettings().enableBlockScoping) {
838
    // Disable parameter TDZ if block scoping support is disabled.
839
1.33k
    hasParamExpressions = false;
840
1.33k
  }
841
842
1.33k
  llvh::SmallVector<Variable *, 4> tdzParams;
843
844
  // Create a variable for every parameter.
845
1.33k
  Value *empty = Builder.getLiteralEmpty();
846
1.33k
  Variable::DeclKind paramKind =
847
1.33k
      hasParamExpressions ? Variable::DeclKind::Let : Variable::DeclKind::Var;
848
1.33k
  for (auto paramDecl : funcNode->getSemInfo()->paramNames) {
849
1.30k
    Identifier paramName = getNameFieldFromID(paramDecl.identifier);
850
1.30k
    LLVM_DEBUG(llvh::dbgs() << "Adding parameter: " << paramName << "\n");
851
1.30k
    auto *paramStorage = Builder.createVariable(
852
1.30k
        newFunc->getFunctionScopeDesc(), paramKind, paramName);
853
1.30k
    if (hasParamExpressions) {
854
      // funcNode has parameter expressions, thus the parameters are first
855
      // copied to tdz variables which need to be initialized to empty.
856
0
      Builder.createStoreFrameInst(empty, paramStorage, currentIRScope_);
857
858
      // Also keep track of all created Variables to copy them into regular Var
859
      // declarations.
860
0
      tdzParams.push_back(paramStorage);
861
0
    }
862
    // Register the storage for the parameter.
863
1.30k
    nameTable_.insert(paramName, paramStorage);
864
1.30k
  }
865
866
1.33k
  uint32_t paramIndex = uint32_t{0} - 1;
867
1.33k
  for (auto &elem : ESTree::getParams(funcNode)) {
868
1.30k
    ESTree::Node *param = &elem;
869
1.30k
    ESTree::Node *init = nullptr;
870
1.30k
    ++paramIndex;
871
872
1.30k
    if (auto *rest = llvh::dyn_cast<ESTree::RestElementNode>(param)) {
873
0
      createLRef(rest->_argument, true)
874
0
          .emitStore(genBuiltinCall(
875
0
              BuiltinMethod::HermesBuiltin_copyRestArgs,
876
0
              Builder.getLiteralNumber(paramIndex)));
877
0
      break;
878
0
    }
879
880
    // Unpack the optional initialization.
881
1.30k
    if (auto *assign = llvh::dyn_cast<ESTree::AssignmentPatternNode>(param)) {
882
0
      param = assign->_left;
883
0
      init = assign->_right;
884
0
    }
885
886
1.30k
    Identifier formalParamName = llvh::isa<ESTree::IdentifierNode>(param)
887
1.30k
        ? getNameFieldFromID(param)
888
1.30k
        : genAnonymousLabelName("param");
889
890
1.30k
    auto *formalParam = Builder.createParameter(newFunc, formalParamName);
891
1.30k
    createLRef(param, true)
892
1.30k
        .emitStore(
893
1.30k
            emitOptionalInitialization(formalParam, init, formalParamName));
894
1.30k
  }
895
896
  // Now copy the TDZ parameters to Var declarations. This improves codegen by
897
  // removing tdz checks when accessing the parameters.
898
1.33k
  assert(
899
1.33k
      (tdzParams.empty() || hasParamExpressions) &&
900
1.33k
      "funcNode does not have param expressions, so it doesn't"
901
1.33k
      " need tdz params.");
902
1.33k
  for (Variable *oldParamStorage : tdzParams) {
903
0
    auto *paramStorage = Builder.createVariable(
904
0
        newFunc->getFunctionScopeDesc(),
905
0
        Variable::DeclKind::Let,
906
0
        oldParamStorage->getName());
907
0
    constexpr bool declInit = true;
908
0
    emitStore(emitLoad(oldParamStorage), paramStorage, declInit);
909
0
    nameTable_.setInCurrentScope(oldParamStorage->getName(), paramStorage);
910
0
  }
911
912
1.33k
  newFunc->setExpectedParamCountIncludingThis(
913
1.33k
      countExpectedArgumentsIncludingThis(funcNode));
914
1.33k
}
915
916
uint32_t ESTreeIRGen::countExpectedArgumentsIncludingThis(
917
1.34k
    ESTree::FunctionLikeNode *funcNode) {
918
  // Start at 1 to account for "this".
919
1.34k
  uint32_t count = 1;
920
1.34k
  for (auto &param : ESTree::getParams(funcNode)) {
921
1.30k
    if (llvh::isa<ESTree::AssignmentPatternNode>(param)) {
922
      // Found an initializer, stop counting expected arguments.
923
0
      break;
924
0
    }
925
1.30k
    ++count;
926
1.30k
  }
927
1.34k
  return count;
928
1.34k
}
929
930
1.33k
void ESTreeIRGen::emitFunctionEpilogue(Value *returnValue) {
931
1.33k
  if (returnValue) {
932
1.33k
    Builder.setLocation(SourceErrorManager::convertEndToLocation(
933
1.33k
        Builder.getFunction()->getSourceRange()));
934
1.33k
    Builder.createReturnInst(returnValue);
935
1.33k
  }
936
937
  // Delete CreateArgumentsInst if it is unused.
938
1.33k
  if (!curFunction()->createArgumentsInst->hasUsers())
939
1.33k
    curFunction()->createArgumentsInst->eraseFromParent();
940
941
1.33k
  curFunction()->function->clearStatementCount();
942
1.33k
}
943
944
0
void ESTreeIRGen::genDummyFunction(Function *dummy) {
945
0
  IRBuilder builder{dummy};
946
947
0
  builder.createThisParameter(dummy);
948
0
  BasicBlock *firstBlock = builder.createBasicBlock(dummy);
949
0
  builder.setInsertionBlock(firstBlock);
950
0
  builder.createUnreachableInst();
951
0
  builder.createReturnInst(builder.getLiteralUndefined());
952
0
}
953
954
/// Generate a function which immediately throws the specified SyntaxError
955
/// message.
956
Function *ESTreeIRGen::genSyntaxErrorFunction(
957
    Module *M,
958
    ScopeDesc *scopeDesc,
959
    Identifier originalName,
960
    SMRange sourceRange,
961
0
    llvh::StringRef error) {
962
0
  IRBuilder builder{M};
963
964
0
  Function *function = builder.createFunction(
965
0
      scopeDesc,
966
0
      originalName,
967
0
      Function::DefinitionKind::ES5Function,
968
0
      true,
969
0
      SourceVisibility::Sensitive,
970
0
      sourceRange,
971
0
      false);
972
973
0
  builder.createThisParameter(function);
974
0
  BasicBlock *firstBlock = builder.createBasicBlock(function);
975
0
  builder.setInsertionBlock(firstBlock);
976
0
  builder.createCreateScopeInst(scopeDesc);
977
978
0
  genRaiseNativeError(builder, NativeErrorTypes::SyntaxError, error);
979
980
0
  return function;
981
0
}
982
983
} // namespace irgen
984
} // namespace hermes