Coverage Report

Created: 2025-08-28 06:48

/src/hermes/lib/IRGen/ESTreeIRGen-expr.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
#include "hermes/Regex/RegexSerialization.h"
10
#include "hermes/Support/UTF8.h"
11
12
#include "llvh/ADT/ScopeExit.h"
13
14
namespace hermes {
15
namespace irgen {
16
17
1.10M
Value *ESTreeIRGen::genExpression(ESTree::Node *expr, Identifier nameHint) {
18
1.10M
  LLVM_DEBUG(
19
1.10M
      llvh::dbgs() << "IRGen expression of type " << expr->getNodeName()
20
1.10M
                   << "\n");
21
1.10M
  IRBuilder::ScopedLocationChange slc(Builder, expr->getDebugLoc());
22
23
  // Handle identifiers.
24
1.10M
  if (auto *Iden = llvh::dyn_cast<ESTree::IdentifierNode>(expr)) {
25
439k
    return genIdentifierExpression(Iden, false);
26
439k
  }
27
28
  // Handle Null Literals.
29
  // http://www.ecma-international.org/ecma-262/6.0/#sec-null-literals
30
666k
  if (llvh::isa<ESTree::NullLiteralNode>(expr)) {
31
0
    return Builder.getLiteralNull();
32
0
  }
33
34
  // Handle String Literals.
35
  // http://www.ecma-international.org/ecma-262/6.0/#sec-literals-string-literals
36
666k
  if (auto *Lit = llvh::dyn_cast<ESTree::StringLiteralNode>(expr)) {
37
10
    LLVM_DEBUG(
38
10
        llvh::dbgs() << "Loading String Literal \"" << Lit->_value << "\"\n");
39
10
    return Builder.getLiteralString(Lit->_value->str());
40
10
  }
41
42
  // Handle Regexp Literals.
43
  // http://www.ecma-international.org/ecma-262/6.0/#sec-literals-regular-expression-literals
44
666k
  if (auto *Lit = llvh::dyn_cast<ESTree::RegExpLiteralNode>(expr)) {
45
388
    return genRegExpLiteral(Lit);
46
388
  }
47
48
  // Handle Boolean Literals.
49
  // http://www.ecma-international.org/ecma-262/6.0/#sec-boolean-literals
50
666k
  if (auto *Lit = llvh::dyn_cast<ESTree::BooleanLiteralNode>(expr)) {
51
0
    LLVM_DEBUG(
52
0
        llvh::dbgs() << "Loading String Literal \"" << Lit->_value << "\"\n");
53
0
    return Builder.getLiteralBool(Lit->_value);
54
0
  }
55
56
  // Handle Number Literals.
57
  // http://www.ecma-international.org/ecma-262/6.0/#sec-literals-numeric-literals
58
666k
  if (auto *Lit = llvh::dyn_cast<ESTree::NumericLiteralNode>(expr)) {
59
432k
    LLVM_DEBUG(
60
432k
        llvh::dbgs() << "Loading Numeric Literal \"" << Lit->_value << "\"\n");
61
432k
    return Builder.getLiteralNumber(Lit->_value);
62
432k
  }
63
64
  // Handle BigInt Literals.
65
  // https://262.ecma-international.org/#sec-ecmascript-language-types-bigint-type
66
233k
  if (auto *Lit = llvh::dyn_cast<ESTree::BigIntLiteralNode>(expr)) {
67
25
    LLVM_DEBUG(
68
25
        llvh::dbgs() << "Loading BitInt Literal \"" << Lit->_bigint->str()
69
25
                     << "\"\n");
70
25
    return Builder.getLiteralBigInt(Lit->_bigint);
71
25
  }
72
73
  // Handle the assignment expression.
74
233k
  if (auto Assign = llvh::dyn_cast<ESTree::AssignmentExpressionNode>(expr)) {
75
1.98k
    return genAssignmentExpr(Assign);
76
1.98k
  }
77
78
  // Handle Call expressions.
79
231k
  if (auto *call = llvh::dyn_cast<ESTree::CallExpressionNode>(expr)) {
80
5
    return genCallExpr(call);
81
5
  }
82
83
  // Handle Call expressions.
84
231k
  if (auto *call = llvh::dyn_cast<ESTree::OptionalCallExpressionNode>(expr)) {
85
0
    return genOptionalCallExpr(call, nullptr);
86
0
  }
87
88
  // Handle the 'new' expressions.
89
231k
  if (auto *newExp = llvh::dyn_cast<ESTree::NewExpressionNode>(expr)) {
90
50
    return genNewExpr(newExp);
91
50
  }
92
93
  // Handle MemberExpression expressions for access property.
94
231k
  if (auto *Mem = llvh::dyn_cast<ESTree::MemberExpressionNode>(expr)) {
95
7.32k
    return genMemberExpression(Mem, MemberExpressionOperation::Load).result;
96
7.32k
  }
97
98
  // Handle MemberExpression expressions for access property.
99
224k
  if (auto *mem = llvh::dyn_cast<ESTree::OptionalMemberExpressionNode>(expr)) {
100
206
    return genOptionalMemberExpression(
101
206
               mem, nullptr, MemberExpressionOperation::Load)
102
206
        .result;
103
206
  }
104
105
  // Handle Array expressions (syntax: [1,2,3]).
106
224k
  if (auto *Arr = llvh::dyn_cast<ESTree::ArrayExpressionNode>(expr)) {
107
113
    return genArrayExpr(Arr);
108
113
  }
109
110
  // Handle object expressions (syntax: {"1" : "2"}).
111
224k
  if (auto *Obj = llvh::dyn_cast<ESTree::ObjectExpressionNode>(expr)) {
112
0
    return genObjectExpr(Obj);
113
0
  }
114
115
  // Handle logical expressions (short circuiting).
116
224k
  if (auto *L = llvh::dyn_cast<ESTree::LogicalExpressionNode>(expr)) {
117
2.00k
    return genLogicalExpression(L);
118
2.00k
  }
119
120
  // Handle Binary Expressions.
121
222k
  if (auto *Bin = llvh::dyn_cast<ESTree::BinaryExpressionNode>(expr)) {
122
105k
    return genBinaryExpression(Bin);
123
105k
  }
124
125
  // Handle Unary operator Expressions.
126
116k
  if (auto *U = llvh::dyn_cast<ESTree::UnaryExpressionNode>(expr)) {
127
64.2k
    return genUnaryExpression(U);
128
64.2k
  }
129
130
  // Handle the 'this' keyword.
131
52.5k
  if (llvh::isa<ESTree::ThisExpressionNode>(expr)) {
132
53
    if (curFunction()->function->getDefinitionKind() ==
133
53
        Function::DefinitionKind::ES6Arrow) {
134
15
      assert(
135
15
          curFunction()->capturedThis &&
136
15
          "arrow function must have a captured this");
137
15
      return Builder.createLoadFrameInst(
138
15
          curFunction()->capturedThis, currentIRScope_);
139
15
    }
140
38
    return curFunction()->function->getThisParameter();
141
53
  }
142
143
52.4k
  if (auto *MP = llvh::dyn_cast<ESTree::MetaPropertyNode>(expr)) {
144
0
    return genMetaProperty(MP);
145
0
  }
146
147
  // Handle function expressions.
148
52.4k
  if (auto *FE = llvh::dyn_cast<ESTree::FunctionExpressionNode>(expr)) {
149
7
    return genFunctionExpression(FE, nameHint);
150
7
  }
151
152
52.4k
  if (auto *AF = llvh::dyn_cast<ESTree::ArrowFunctionExpressionNode>(expr)) {
153
1.76k
    return genArrowFunctionExpression(AF, nameHint);
154
1.76k
  }
155
156
50.6k
  if (auto *U = llvh::dyn_cast<ESTree::UpdateExpressionNode>(expr)) {
157
0
    return genUpdateExpr(U);
158
0
  }
159
160
50.6k
  if (auto *C = llvh::dyn_cast<ESTree::ConditionalExpressionNode>(expr)) {
161
5.06k
    return genConditionalExpr(C);
162
5.06k
  }
163
164
45.6k
  if (auto *Sq = llvh::dyn_cast<ESTree::SequenceExpressionNode>(expr)) {
165
251
    return genSequenceExpr(Sq);
166
251
  }
167
168
45.3k
  if (auto *Tl = llvh::dyn_cast<ESTree::TemplateLiteralNode>(expr)) {
169
40.3k
    return genTemplateLiteralExpr(Tl);
170
40.3k
  }
171
172
5.00k
  if (auto *Tt = llvh::dyn_cast<ESTree::TaggedTemplateExpressionNode>(expr)) {
173
5.00k
    return genTaggedTemplateExpr(Tt);
174
5.00k
  }
175
176
0
  if (auto *Y = llvh::dyn_cast<ESTree::YieldExpressionNode>(expr)) {
177
0
    return Y->_delegate ? genYieldStarExpr(Y) : genYieldExpr(Y);
178
0
  }
179
180
0
  if (auto *A = llvh::dyn_cast<ESTree::AwaitExpressionNode>(expr)) {
181
0
    return genAwaitExpr(A);
182
0
  }
183
184
0
  Builder.getModule()->getContext().getSourceErrorManager().error(
185
0
      expr->getSourceRange(), Twine("Invalid expression encountered"));
186
0
  return Builder.getLiteralUndefined();
187
0
}
188
189
void ESTreeIRGen::genExpressionBranch(
190
    ESTree::Node *expr,
191
    BasicBlock *onTrue,
192
    BasicBlock *onFalse,
193
5.06k
    BasicBlock *onNullish) {
194
5.06k
  switch (expr->getKind()) {
195
0
    case ESTree::NodeKind::LogicalExpression:
196
0
      return genLogicalExpressionBranch(
197
0
          cast<ESTree::LogicalExpressionNode>(expr),
198
0
          onTrue,
199
0
          onFalse,
200
0
          onNullish);
201
202
2.76k
    case ESTree::NodeKind::UnaryExpression: {
203
2.76k
      auto *e = cast<ESTree::UnaryExpressionNode>(expr);
204
2.76k
      switch (UnaryOperatorInst::parseOperator(e->_operator->str())) {
205
0
        case UnaryOperatorInst::OpKind::BangKind:
206
          // Do not propagate onNullish here because !expr cannot be nullish.
207
0
          return genExpressionBranch(e->_argument, onFalse, onTrue, nullptr);
208
2.76k
        default:
209
2.76k
          break;
210
2.76k
      }
211
212
2.76k
      break;
213
2.76k
    }
214
215
2.76k
    case ESTree::NodeKind::SequenceExpression: {
216
0
      auto *e = cast<ESTree::SequenceExpressionNode>(expr);
217
218
0
      ESTree::NodePtr last = nullptr;
219
0
      for (auto &ex : e->_expressions) {
220
0
        if (last)
221
0
          genExpression(last);
222
0
        last = &ex;
223
0
      }
224
0
      if (last)
225
0
        genExpressionBranch(last, onTrue, onFalse, onNullish);
226
0
      return;
227
2.76k
    }
228
229
2.30k
    default:
230
2.30k
      break;
231
5.06k
  }
232
233
5.06k
  Value *condVal = genExpression(expr);
234
5.06k
  if (onNullish) {
235
0
    Value *isNullish = Builder.createBinaryOperatorInst(
236
0
        condVal,
237
0
        Builder.getLiteralNull(),
238
0
        BinaryOperatorInst::OpKind::EqualKind);
239
0
    BasicBlock *notNullishBB = Builder.createBasicBlock(Builder.getFunction());
240
0
    Builder.createCondBranchInst(isNullish, onNullish, notNullishBB);
241
0
    Builder.setInsertionBlock(notNullishBB);
242
0
  }
243
5.06k
  Builder.createCondBranchInst(condVal, onTrue, onFalse);
244
5.06k
}
245
246
114
Value *ESTreeIRGen::genArrayFromElements(ESTree::NodeList &list) {
247
114
  LLVM_DEBUG(llvh::dbgs() << "Initializing a new array\n");
248
114
  AllocArrayInst::ArrayValueList elements;
249
250
  // Precalculate the minimum number of elements in case we need to call
251
  // AllocArrayInst at some point, as well as find out whether we have a spread
252
  // element (which will result in the final array having variable length).
253
114
  unsigned minElements = 0;
254
114
  bool variableLength = false;
255
318k
  for (auto &E : list) {
256
318k
    if (llvh::isa<ESTree::SpreadElementNode>(&E)) {
257
7
      variableLength = true;
258
7
      continue;
259
7
    }
260
318k
    ++minElements;
261
318k
  }
262
263
  // We store consecutive elements until we encounter elision,
264
  // or we enounter a non-literal in limited-register mode.
265
  // The rest of them has to be initialized through property sets.
266
267
  // If we have a variable length array, then we store the next index in
268
  // a stack location `nextIndex`, to be updated when we encounter spread
269
  // elements. Otherwise, we simply count them in `count`.
270
114
  unsigned count = 0;
271
114
  AllocStackInst *nextIndex = nullptr;
272
114
  if (variableLength) {
273
    // Avoid emitting the extra instructions unless we actually need to,
274
    // to simplify tests and because it's easy.
275
7
    nextIndex = Builder.createAllocStackInst("nextIndex");
276
7
    Builder.createStoreStackInst(Builder.getLiteralPositiveZero(), nextIndex);
277
7
  }
278
279
114
  bool consecutive = true;
280
114
  auto codeGenOpts = Mod->getContext().getCodeGenerationSettings();
281
114
  AllocArrayInst *allocArrayInst = nullptr;
282
318k
  for (auto &E : list) {
283
318k
    Value *value{nullptr};
284
318k
    bool isSpread = false;
285
318k
    if (!llvh::isa<ESTree::EmptyNode>(&E)) {
286
318k
      if (auto *spread = llvh::dyn_cast<ESTree::SpreadElementNode>(&E)) {
287
7
        isSpread = true;
288
7
        value = genExpression(spread->_argument);
289
318k
      } else {
290
318k
        value = genExpression(&E);
291
318k
      }
292
318k
    }
293
318k
    if (!value ||
294
318k
        (!llvh::isa<Literal>(value) && !codeGenOpts.unlimitedRegisters) ||
295
318k
        isSpread) {
296
      // This is either an elision,
297
      // or a non-literal in limited-register mode,
298
      // or a spread element.
299
97
      if (consecutive) {
300
        // So far we have been storing elements consecutively,
301
        // but not anymore, time to create the array.
302
53
        allocArrayInst = Builder.createAllocArrayInst(elements, minElements);
303
53
        consecutive = false;
304
53
      }
305
97
    }
306
318k
    if (isSpread) {
307
      // Spread the SpreadElement argument into the array.
308
      // HermesInternal.arraySpread returns the new value of nextIndex,
309
      // so update nextIndex accordingly and finish this iteration of the loop.
310
7
      auto *newNextIndex = genBuiltinCall(
311
7
          BuiltinMethod::HermesBuiltin_arraySpread,
312
7
          {allocArrayInst, value, Builder.createLoadStackInst(nextIndex)});
313
7
      Builder.createStoreStackInst(newNextIndex, nextIndex);
314
7
      continue;
315
7
    }
316
    // The element is not a spread element, so perform the store here.
317
318k
    if (value) {
318
318k
      if (consecutive) {
319
123k
        elements.push_back(value);
320
195k
      } else {
321
195k
        Builder.createStoreOwnPropertyInst(
322
195k
            value,
323
195k
            allocArrayInst,
324
195k
            variableLength ? cast<Value>(Builder.createLoadStackInst(nextIndex))
325
195k
                           : cast<Value>(Builder.getLiteralNumber(count)),
326
195k
            IRBuilder::PropEnumerable::Yes);
327
195k
      }
328
318k
    }
329
    // Update the next index or the count depending on if it's a variable length
330
    // array.
331
318k
    if (variableLength) {
332
      // We perform this update on any leading elements before the first spread
333
      // element as well, but the optimizer will eliminate the extra adds
334
      // because we know the initial value (0) and how incrementing works.
335
35
      Builder.createStoreStackInst(
336
35
          Builder.createBinaryOperatorInst(
337
35
              Builder.createLoadStackInst(nextIndex),
338
35
              Builder.getLiteralNumber(1),
339
35
              BinaryOperatorInst::OpKind::AddKind),
340
35
          nextIndex);
341
318k
    } else {
342
318k
      count++;
343
318k
    }
344
318k
  }
345
346
114
  if (!allocArrayInst) {
347
61
    assert(
348
61
        !variableLength &&
349
61
        "variable length arrays must allocate their own arrays");
350
61
    allocArrayInst = Builder.createAllocArrayInst(elements, list.size());
351
61
  }
352
114
  if (!list.empty() && llvh::isa<ESTree::EmptyNode>(&list.back())) {
353
    // Last element is an elision, VM cannot derive the length properly.
354
    // We have to explicitly set it.
355
2
    Value *newLength;
356
2
    if (variableLength)
357
1
      newLength = Builder.createLoadStackInst(nextIndex);
358
1
    else
359
1
      newLength = Builder.getLiteralNumber(count);
360
2
    Builder.createStorePropertyInst(
361
2
        newLength, allocArrayInst, llvh::StringRef("length"));
362
2
  }
363
114
  return allocArrayInst;
364
114
}
365
366
113
Value *ESTreeIRGen::genArrayExpr(ESTree::ArrayExpressionNode *Expr) {
367
113
  return genArrayFromElements(Expr->_elements);
368
113
}
369
370
5
Value *ESTreeIRGen::genCallExpr(ESTree::CallExpressionNode *call) {
371
5
  LLVM_DEBUG(llvh::dbgs() << "IRGen 'call' statement/expression.\n");
372
373
  // Check for a direct call to eval().
374
5
  if (auto *identNode = llvh::dyn_cast<ESTree::IdentifierNode>(call->_callee)) {
375
4
    if (Identifier::getFromPointer(identNode->_name) == identEval_) {
376
0
      auto *evalVar = nameTable_.lookup(identEval_);
377
0
      if (!evalVar || llvh::isa<GlobalObjectProperty>(evalVar))
378
0
        return genCallEvalExpr(call);
379
0
    }
380
4
  }
381
382
5
  Value *thisVal;
383
5
  Value *callee;
384
385
  // Handle MemberExpression expression calls that sets the 'this' property.
386
5
  if (auto *Mem = llvh::dyn_cast<ESTree::MemberExpressionNode>(call->_callee)) {
387
0
    MemberExpressionResult memResult =
388
0
        genMemberExpression(Mem, MemberExpressionOperation::Load);
389
390
    // Call the callee with obj as the 'this' pointer.
391
0
    thisVal = memResult.base;
392
0
    callee = memResult.result;
393
5
  } else if (
394
5
      auto *Mem =
395
5
          llvh::dyn_cast<ESTree::OptionalMemberExpressionNode>(call->_callee)) {
396
0
    MemberExpressionResult memResult = genOptionalMemberExpression(
397
0
        Mem, nullptr, MemberExpressionOperation::Load);
398
399
    // Call the callee with obj as the 'this' pointer.
400
0
    thisVal = memResult.base;
401
0
    callee = memResult.result;
402
5
  } else {
403
5
    thisVal = Builder.getLiteralUndefined();
404
5
    callee = genExpression(call->_callee);
405
5
  }
406
407
5
  return emitCall(call, callee, thisVal);
408
5
}
409
410
Value *ESTreeIRGen::genOptionalCallExpr(
411
    ESTree::OptionalCallExpressionNode *call,
412
32
    BasicBlock *shortCircuitBB) {
413
32
  PhiInst::ValueListType values;
414
32
  PhiInst::BasicBlockListType blocks;
415
416
  // true when this is the genOptionalCallExpr call containing
417
  // the logic for shortCircuitBB.
418
32
  bool isFirstOptional = shortCircuitBB == nullptr;
419
420
  // If isFirstOptional, the final result will be computed in continueBB and
421
  // returned.
422
32
  BasicBlock *continueBB = nullptr;
423
424
32
  if (!shortCircuitBB) {
425
    // If shortCircuitBB is null, then this is the outermost in the optional
426
    // chain, so we must create it here and pass it through to every other
427
    // OptionalCallExpression and OptionalMemberExpression in the chain.
428
0
    continueBB = Builder.createBasicBlock(Builder.getFunction());
429
0
    auto *insertionBB = Builder.getInsertionBlock();
430
0
    shortCircuitBB = Builder.createBasicBlock(Builder.getFunction());
431
0
    Builder.setInsertionBlock(shortCircuitBB);
432
0
    values.push_back(Builder.getLiteralUndefined());
433
0
    blocks.push_back(shortCircuitBB);
434
0
    Builder.createBranchInst(continueBB);
435
0
    Builder.setInsertionBlock(insertionBB);
436
0
  }
437
438
32
  Value *thisVal;
439
32
  Value *callee;
440
441
  // Handle MemberExpression expression calls that sets the 'this' property.
442
32
  if (auto *me = llvh::dyn_cast<ESTree::MemberExpressionNode>(call->_callee)) {
443
0
    MemberExpressionResult memResult =
444
0
        genMemberExpression(me, MemberExpressionOperation::Load);
445
446
    // Call the callee with obj as the 'this' pointer.
447
0
    thisVal = memResult.base;
448
0
    callee = memResult.result;
449
32
  } else if (
450
32
      auto *ome =
451
32
          llvh::dyn_cast<ESTree::OptionalMemberExpressionNode>(call->_callee)) {
452
32
    MemberExpressionResult memResult = genOptionalMemberExpression(
453
32
        ome, shortCircuitBB, MemberExpressionOperation::Load);
454
455
    // Call the callee with obj as the 'this' pointer.
456
32
    thisVal = memResult.base;
457
32
    callee = memResult.result;
458
32
  } else if (
459
0
      auto *oce =
460
0
          llvh::dyn_cast<ESTree::OptionalCallExpressionNode>(call->_callee)) {
461
0
    thisVal = Builder.getLiteralUndefined();
462
0
    callee = genOptionalCallExpr(oce, shortCircuitBB);
463
0
  } else {
464
0
    thisVal = Builder.getLiteralUndefined();
465
0
    callee = genExpression(getCallee(call));
466
0
  }
467
468
32
  if (call->_optional) {
469
0
    BasicBlock *evalRHSBB = Builder.createBasicBlock(Builder.getFunction());
470
471
    // If callee is undefined or null, then return undefined.
472
    // NOTE: We use `obj == null` to account for both null and undefined.
473
0
    Builder.createCondBranchInst(
474
0
        Builder.createBinaryOperatorInst(
475
0
            callee,
476
0
            Builder.getLiteralNull(),
477
0
            BinaryOperatorInst::OpKind::EqualKind),
478
0
        shortCircuitBB,
479
0
        evalRHSBB);
480
481
    // baseValue is not undefined or null.
482
0
    Builder.setInsertionBlock(evalRHSBB);
483
0
  }
484
485
32
  Value *callResult = emitCall(call, callee, thisVal);
486
487
32
  if (isFirstOptional) {
488
0
    values.push_back(callResult);
489
0
    blocks.push_back(Builder.getInsertionBlock());
490
0
    Builder.createBranchInst(continueBB);
491
492
0
    Builder.setInsertionBlock(continueBB);
493
0
    return Builder.createPhiInst(values, blocks);
494
0
  }
495
496
  // If this isn't the first optional, no Phi needed, just return the
497
  // callResult.
498
32
  return callResult;
499
32
}
500
501
/// \return a LiteralString with a textual representation of given \p call
502
/// expression. This representation is built from the original source code, with
503
/// some changes:
504
///
505
/// 1. unprintable character, new line, and spaces following new lines, are not
506
///    emitted.
507
/// 2. output is limited to kMaxTextifiedCalleeSizeUTF8Chars. If the source code
508
/// is longer than the maximum number of characters, then the returned callee
509
/// will look like
510
///
511
///  source code     : aaaaaaaaaa[.]+bbbbbbbbbb
512
///  textified callee: "aaaaaaaaaa(...)bbbbbbbbbb"
513
static LiteralString *getTextifiedCallExpr(
514
    IRBuilder &builder,
515
37
    ESTree::Node *callee) {
516
37
  constexpr uint32_t kMaxTextifiedCalleeSizeUTF8Chars = 64;
517
  // Pessimizing the maximum buffer size for the textified callee as if all
518
  // characters were 4 bytes.
519
37
  llvh::SmallVector<char, kMaxTextifiedCalleeSizeUTF8Chars * 4> textifiedCallee;
520
37
  llvh::raw_svector_ostream OS(textifiedCallee);
521
522
  // Count of how many UTF8 character are on the textified callee string.
523
37
  uint32_t numUTF8Chars = 0;
524
37
  const char *begin = callee->getSourceRange().Start.getPointer();
525
37
  const char *end = callee->getSourceRange().End.getPointer();
526
527
37
  const char *pos = begin;
528
529
  /// Helper function that scans the input source code searching for the next
530
  /// UTF8 char starting at \p iter. \return a StringRef with the chars that
531
  /// form the next UTF8 char on the input, or None if the input has been
532
  /// exhausted. Upon return, \p iter will be modified 1-past the last char
533
  /// consumed from the input.
534
86.8k
  auto nextUTF8Char = [end](const char *&iter) -> OptValue<llvh::StringRef> {
535
86.8k
    assert(iter < end && "iter is past end");
536
86.8k
    const char *start;
537
86.8k
    bool skipSpace = false;
538
86.8k
    bool newLine;
539
86.8k
    bool unprintableChar;
540
    // The function may need to decode several UTF8 charaters to skip new lines,
541
    // spaces following new lines, and unprintable characters.
542
86.9k
    do {
543
86.9k
      if (iter == end) {
544
0
        return llvh::None;
545
0
      }
546
547
      // From start, where does the current UTF8 character ends?
548
86.9k
      start = iter;
549
86.9k
      for (++iter; iter < end && isUTF8ContinuationByte(*iter); ++iter) {
550
        // nothing
551
43
      }
552
553
86.9k
      newLine = *start == '\n';
554
86.9k
      skipSpace |= newLine;
555
86.9k
      unprintableChar = static_cast<uint8_t>(*start) < 32;
556
86.9k
    } while (unprintableChar || newLine || (skipSpace && *start == ' '));
557
558
86.8k
    const size_t utf8CharLength = static_cast<size_t>(iter - start);
559
86.8k
    return llvh::StringRef{start, utf8CharLength};
560
86.8k
  };
561
562
  // The algorithm is split in three separate steps:
563
  // 1. Find the range in the input source that contains the first half of the
564
  //    UTF8 characters that should be present on the output.
565
  // 2. Find the window into the input source starting at the end of the range
566
  //    computed in 1. and containing another half of the maximum output length.
567
  //    This window is [mark, pos).
568
  // 3. Slide the [mark, pos) window found in 2 until pos equals end.
569
  //
570
  // If the input is exhausted in 1. or 2., then the output string will contain
571
  // a "copy" of the input source (minus the characters listed above); it will
572
  // otherwise be prefix"(...)"suffix, with prefix being the first
573
  // kMaxTextifiedCalleeSizeUTF8Chars / 2 UTF8 chars in the input source, and
574
  // suffix, the last kMaxTextifiedCalleeSizeUTF8Chars / 2 UTF8 chars.
575
576
  // Scan the input string starting from the first position until half of the
577
  // maximum of allowed character have been scanned.
578
1.00k
  while (pos < end && numUTF8Chars < kMaxTextifiedCalleeSizeUTF8Chars / 2) {
579
969
    if (auto ch = nextUTF8Char(pos)) {
580
969
      ++numUTF8Chars;
581
969
      OS << *ch;
582
969
    }
583
969
  }
584
585
37
  assert(
586
37
      (pos == end || numUTF8Chars == kMaxTextifiedCalleeSizeUTF8Chars / 2) &&
587
37
      "Invalid source range");
588
589
  // Now save the current position, and advance it until the end of the buffer,
590
  // or until enough UTF8 characters are found.
591
37
  const char *mark = pos;
592
451
  while (pos < end && numUTF8Chars < kMaxTextifiedCalleeSizeUTF8Chars) {
593
414
    if (nextUTF8Char(pos)) {
594
414
      ++numUTF8Chars;
595
414
    }
596
414
  }
597
598
37
  assert(
599
37
      (pos == end || numUTF8Chars == kMaxTextifiedCalleeSizeUTF8Chars) &&
600
37
      "Invalid source range");
601
602
37
  if (pos < end) {
603
    // Slide the suffix window if pos is not at the end of the input.
604
9
    OS << "(...)";
605
606
42.5k
    while (pos < end) {
607
42.5k
      auto ch = nextUTF8Char(mark);
608
42.5k
      assert(ch && "should have a character");
609
42.5k
      (void)ch;
610
42.5k
      nextUTF8Char(pos);
611
42.5k
    }
612
9
  }
613
614
  // The input should be exhausted by now, and pos should be equal to end --
615
  // meaning all characters have been decoded.
616
37
  assert(pos == end && "Invalid source range");
617
618
  // Now add all characters between mark and end to the textified callable.
619
451
  while (mark < end) {
620
414
    auto ch = nextUTF8Char(mark);
621
414
    assert(ch && "should have a character");
622
414
    OS << *ch;
623
414
  }
624
625
37
  return builder.getLiteralString(OS.str());
626
37
}
627
628
Value *ESTreeIRGen::emitCall(
629
    ESTree::CallExpressionLikeNode *call,
630
    Value *callee,
631
37
    Value *thisVal) {
632
37
  bool hasSpread = false;
633
37
  for (auto &arg : getArguments(call)) {
634
4
    if (llvh::isa<ESTree::SpreadElementNode>(&arg)) {
635
0
      hasSpread = true;
636
0
    }
637
4
  }
638
639
37
  if (!hasSpread) {
640
37
    CallInst::ArgumentList args;
641
37
    for (auto &arg : getArguments(call)) {
642
4
      args.push_back(genExpression(&arg));
643
4
    }
644
645
37
    return Builder.createCallInst(
646
37
        getTextifiedCallExpr(Builder, getCallee(call)), callee, thisVal, args);
647
37
  }
648
649
  // Otherwise, there exists a spread argument, so the number of arguments
650
  // is variable.
651
  // Generate IR for this by creating an array and populating it with the
652
  // arguments, then calling HermesInternal.apply.
653
0
  auto *args = genArrayFromElements(getArguments(call));
654
0
  return genBuiltinCall(
655
0
      BuiltinMethod::HermesBuiltin_apply, {callee, args, thisVal});
656
37
}
657
658
ESTreeIRGen::MemberExpressionResult ESTreeIRGen::genMemberExpression(
659
    ESTree::MemberExpressionNode *mem,
660
7.33k
    MemberExpressionOperation op) {
661
7.33k
  Value *baseValue = genExpression(mem->_object);
662
7.33k
  Value *prop = genMemberExpressionProperty(mem);
663
7.33k
  switch (op) {
664
7.32k
    case MemberExpressionOperation::Load:
665
7.32k
      return MemberExpressionResult{
666
7.32k
          Builder.createLoadPropertyInst(baseValue, prop), baseValue};
667
2
    case MemberExpressionOperation::Delete:
668
2
      return MemberExpressionResult{
669
2
          Builder.createDeletePropertyInst(baseValue, prop), baseValue};
670
7.33k
  }
671
7.33k
  llvm_unreachable("No other kind of member expression");
672
7.33k
}
673
674
ESTreeIRGen::MemberExpressionResult ESTreeIRGen::genOptionalMemberExpression(
675
    ESTree::OptionalMemberExpressionNode *mem,
676
    BasicBlock *shortCircuitBB,
677
6.76k
    MemberExpressionOperation op) {
678
6.76k
  PhiInst::ValueListType values;
679
6.76k
  PhiInst::BasicBlockListType blocks;
680
681
  // true when this is the genOptionalMemberExpression call containing
682
  // the logic for shortCircuitBB.
683
6.76k
  bool isFirstOptional = shortCircuitBB == nullptr;
684
685
  // If isFirstOptional, the final result will be computed in continueBB and
686
  // returned.
687
6.76k
  BasicBlock *continueBB = nullptr;
688
689
6.76k
  if (isFirstOptional) {
690
    // If shortCircuitBB is null, then this is the outermost in the optional
691
    // chain, so we must create it here and pass it through to every other
692
    // OptionalCallExpression and OptionalMemberExpression in the chain.
693
206
    continueBB = Builder.createBasicBlock(Builder.getFunction());
694
206
    auto *insertionBB = Builder.getInsertionBlock();
695
206
    shortCircuitBB = Builder.createBasicBlock(Builder.getFunction());
696
206
    Builder.setInsertionBlock(shortCircuitBB);
697
206
    values.push_back(Builder.getLiteralUndefined());
698
206
    blocks.push_back(shortCircuitBB);
699
206
    Builder.createBranchInst(continueBB);
700
206
    Builder.setInsertionBlock(insertionBB);
701
206
  }
702
703
6.76k
  Value *baseValue = nullptr;
704
6.76k
  if (ESTree::OptionalMemberExpressionNode *ome =
705
6.76k
          llvh::dyn_cast<ESTree::OptionalMemberExpressionNode>(mem->_object)) {
706
6.52k
    baseValue = genOptionalMemberExpression(
707
6.52k
                    ome, shortCircuitBB, MemberExpressionOperation::Load)
708
6.52k
                    .result;
709
6.52k
  } else if (
710
238
      ESTree::OptionalCallExpressionNode *oce =
711
238
          llvh::dyn_cast<ESTree::OptionalCallExpressionNode>(mem->_object)) {
712
32
    baseValue = genOptionalCallExpr(oce, shortCircuitBB);
713
206
  } else {
714
206
    baseValue = genExpression(mem->_object);
715
206
  }
716
717
6.76k
  if (mem->_optional) {
718
404
    BasicBlock *evalRHSBB = Builder.createBasicBlock(Builder.getFunction());
719
720
    // If baseValue is undefined or null, then return undefined.
721
    // NOTE: We use `obj == null` to account for both null and undefined.
722
404
    Builder.createCondBranchInst(
723
404
        Builder.createBinaryOperatorInst(
724
404
            baseValue,
725
404
            Builder.getLiteralNull(),
726
404
            BinaryOperatorInst::OpKind::EqualKind),
727
404
        shortCircuitBB,
728
404
        evalRHSBB);
729
730
    // baseValue is not undefined, look up the property properly.
731
404
    Builder.setInsertionBlock(evalRHSBB);
732
404
  }
733
734
6.76k
  Value *prop = genMemberExpressionProperty(mem);
735
6.76k
  Value *result = nullptr;
736
6.76k
  switch (op) {
737
6.76k
    case MemberExpressionOperation::Load:
738
6.76k
      result = Builder.createLoadPropertyInst(baseValue, prop);
739
6.76k
      break;
740
0
    case MemberExpressionOperation::Delete:
741
0
      result = Builder.createDeletePropertyInst(baseValue, prop);
742
0
      break;
743
6.76k
  }
744
6.76k
  assert(result && "result must be set");
745
746
6.76k
  if (isFirstOptional) {
747
206
    values.push_back(result);
748
206
    blocks.push_back(Builder.getInsertionBlock());
749
206
    Builder.createBranchInst(continueBB);
750
751
206
    Builder.setInsertionBlock(continueBB);
752
206
    return {Builder.createPhiInst(values, blocks), baseValue};
753
206
  }
754
755
  // If this isn't the first optional, no Phi needed, just return the result.
756
6.55k
  return {result, baseValue};
757
6.76k
}
758
759
0
Value *ESTreeIRGen::genCallEvalExpr(ESTree::CallExpressionNode *call) {
760
0
  if (call->_arguments.empty()) {
761
0
    Mod->getContext().getSourceErrorManager().warning(
762
0
        call->getSourceRange(), "eval() without arguments returns undefined");
763
0
    return Builder.getLiteralUndefined();
764
0
  }
765
766
0
  Mod->getContext().getSourceErrorManager().warning(
767
0
      Warning::DirectEval,
768
0
      call->getSourceRange(),
769
0
      "Direct call to eval(), but lexical scope is not supported.");
770
771
0
  llvh::SmallVector<Value *, 1> args;
772
0
  for (auto &arg : call->_arguments) {
773
0
    args.push_back(genExpression(&arg));
774
0
  }
775
776
0
  if (args.size() > 1) {
777
0
    Mod->getContext().getSourceErrorManager().warning(
778
0
        call->getSourceRange(), "Extra eval() arguments are ignored");
779
0
  }
780
781
0
  bool isStrict = Builder.getInsertionBlock()->getParent()->isStrictMode();
782
0
  return Builder.createDirectEvalInst(
783
0
      args[0], Builder.getLiteralBool(isStrict));
784
0
}
785
786
/// Convert a property key node to its JavaScript string representation.
787
static llvh::StringRef propertyKeyAsString(
788
    llvh::SmallVectorImpl<char> &storage,
789
0
    ESTree::Node *Key) {
790
  // Handle String Literals.
791
  // http://www.ecma-international.org/ecma-262/6.0/#sec-literals-string-literals
792
0
  if (auto *Lit = llvh::dyn_cast<ESTree::StringLiteralNode>(Key)) {
793
0
    LLVM_DEBUG(
794
0
        llvh::dbgs() << "Loading String Literal \"" << Lit->_value << "\"\n");
795
0
    return Lit->_value->str();
796
0
  }
797
798
  // Handle identifiers as if they are String Literals.
799
0
  if (auto *Iden = llvh::dyn_cast<ESTree::IdentifierNode>(Key)) {
800
0
    LLVM_DEBUG(
801
0
        llvh::dbgs() << "Loading String Literal \"" << Iden->_name << "\"\n");
802
0
    return Iden->_name->str();
803
0
  }
804
805
  // Handle Number Literals.
806
  // http://www.ecma-international.org/ecma-262/6.0/#sec-literals-numeric-literals
807
0
  if (auto *Lit = llvh::dyn_cast<ESTree::NumericLiteralNode>(Key)) {
808
0
    LLVM_DEBUG(
809
0
        llvh::dbgs() << "Loading Numeric Literal \"" << Lit->_value << "\"\n");
810
0
    storage.resize(NUMBER_TO_STRING_BUF_SIZE);
811
0
    auto len = numberToString(Lit->_value, storage.data(), storage.size());
812
0
    return llvh::StringRef(storage.begin(), len);
813
0
  }
814
815
0
  llvm_unreachable("Don't know this kind of property key");
816
0
  return llvh::StringRef();
817
0
}
818
819
0
Value *ESTreeIRGen::genObjectExpr(ESTree::ObjectExpressionNode *Expr) {
820
0
  LLVM_DEBUG(llvh::dbgs() << "Initializing a new object\n");
821
822
  /// Store information about a property. Is it an accessor (getter/setter) or
823
  /// a value, and the actual value.
824
0
  class PropertyValue {
825
0
   public:
826
    /// Is this a getter/setter value.
827
0
    bool isAccessor = false;
828
    /// Tracks the state of generating IR for this value.
829
0
    enum { None, Placeholder, IRGenerated } state{None};
830
    /// The value, if this is a regular property
831
0
    ESTree::Node *valueNode{};
832
    /// Getter accessor, if this is an accessor property.
833
0
    ESTree::FunctionExpressionNode *getterNode{};
834
    /// Setter accessor, if this is an accessor property.
835
0
    ESTree::FunctionExpressionNode *setterNode{};
836
837
0
    SMRange getSourceRange() {
838
0
      if (valueNode) {
839
0
        return valueNode->getSourceRange();
840
0
      }
841
842
0
      if (getterNode) {
843
0
        return getterNode->getSourceRange();
844
0
      }
845
846
0
      if (setterNode) {
847
0
        return setterNode->getSourceRange();
848
0
      }
849
850
0
      llvm_unreachable("Unset node has no location info");
851
0
    }
852
853
0
    void setValue(ESTree::Node *val) {
854
0
      isAccessor = false;
855
0
      valueNode = val;
856
0
      getterNode = setterNode = nullptr;
857
0
    }
858
0
    void setGetter(ESTree::FunctionExpressionNode *get) {
859
0
      if (!isAccessor) {
860
0
        valueNode = nullptr;
861
0
        setterNode = nullptr;
862
0
        isAccessor = true;
863
0
      }
864
0
      getterNode = get;
865
0
    }
866
0
    void setSetter(ESTree::FunctionExpressionNode *set) {
867
0
      if (!isAccessor) {
868
0
        valueNode = nullptr;
869
0
        getterNode = nullptr;
870
0
        isAccessor = true;
871
0
      }
872
0
      setterNode = set;
873
0
    }
874
0
  };
875
876
  // First accumulate all getters and setters. We walk all properties, convert
877
  // them to string and store the value into propMap, possibly overwriting the
878
  // previous value.
879
  // Note that computed properties are not stored in the propMap as we do not
880
  // know the keys at compilation time.
881
0
  llvh::StringMap<PropertyValue> propMap;
882
  // The first location where a given property name is encountered.
883
0
  llvh::StringMap<SMRange> firstLocMap;
884
0
  llvh::SmallVector<char, 32> stringStorage;
885
  /// The optional __proto__ property.
886
0
  ESTree::PropertyNode *protoProperty = nullptr;
887
888
0
  uint32_t numComputed = 0;
889
890
0
  for (auto &P : Expr->_properties) {
891
0
    if (llvh::isa<ESTree::SpreadElementNode>(&P)) {
892
0
      continue;
893
0
    }
894
895
    // We are reusing the storage, so make sure it is cleared at every
896
    // iteration.
897
0
    stringStorage.clear();
898
899
0
    auto *prop = cast<ESTree::PropertyNode>(&P);
900
0
    if (prop->_computed) {
901
      // Can't store any useful information if the name is computed.
902
      // Just generate the code in the next loop.
903
0
      ++numComputed;
904
0
      continue;
905
0
    }
906
907
0
    auto propName = propertyKeyAsString(stringStorage, prop->_key);
908
909
    // protoProperty should only be recorded if the property is not a method
910
    // nor a shorthand value.
911
0
    if (prop->_kind->str() == "init" && propName == "__proto__" &&
912
0
        !prop->_method && !prop->_shorthand) {
913
0
      if (!protoProperty) {
914
0
        protoProperty = prop;
915
0
      } else {
916
0
        Builder.getModule()->getContext().getSourceErrorManager().error(
917
0
            prop->getSourceRange(),
918
0
            "__proto__ was set multiple times in the object definition.");
919
0
        Builder.getModule()->getContext().getSourceErrorManager().note(
920
0
            protoProperty->getSourceRange(), "The first definition was here.");
921
0
      }
922
0
      continue;
923
0
    }
924
925
0
    PropertyValue *propValue = &propMap[propName];
926
0
    if (prop->_kind->str() == "get") {
927
0
      propValue->setGetter(cast<ESTree::FunctionExpressionNode>(prop->_value));
928
0
    } else if (prop->_kind->str() == "set") {
929
0
      propValue->setSetter(cast<ESTree::FunctionExpressionNode>(prop->_value));
930
0
    } else {
931
0
      assert(prop->_kind->str() == "init" && "invalid PropertyNode kind");
932
      // We record the propValue if this is a regular property
933
0
      propValue->setValue(prop->_value);
934
0
    }
935
936
0
    std::string key = (prop->_kind->str() + propName).str();
937
0
    auto iterAndSuccess = firstLocMap.try_emplace(key, prop->getSourceRange());
938
0
    if (!iterAndSuccess.second) {
939
0
      Builder.getModule()->getContext().getSourceErrorManager().warning(
940
0
          prop->getSourceRange(),
941
0
          Twine("the property \"") + propName +
942
0
              "\" was set multiple times in the object definition.");
943
944
0
      Builder.getModule()->getContext().getSourceErrorManager().note(
945
0
          iterAndSuccess.first->second, "The first definition was here.");
946
0
    }
947
0
  }
948
949
  /// Attempt to determine whether we can directly use the value of the
950
  /// __proto__ property as a parent when creating the object for an object
951
  /// initializer, instead of setting it later with
952
  /// HermesInternal.silentSetPrototypeOf(). That is not possible to determine
953
  /// statically in the general case, but we can check for the simple cases:
954
  /// - __proto__ property is first.
955
  /// - the value of __proto__ is constant.
956
0
  Value *objectParent = nullptr;
957
0
  if (protoProperty &&
958
0
      (&Expr->_properties.front() == protoProperty ||
959
0
       isConstantExpr(protoProperty->_value))) {
960
0
    objectParent = genExpression(protoProperty->_value);
961
0
  }
962
963
  // Allocate a new javascript object on the heap.
964
0
  auto Obj =
965
0
      Builder.createAllocObjectInst(propMap.size() + numComputed, objectParent);
966
967
  // haveSeenComputedProp tracks whether we have processed a computed property.
968
  // Once we do, for all future properties, we can no longer generate
969
  // StoreNewOwnPropertyInst because the computed property could have already
970
  // defined any property.
971
0
  bool haveSeenComputedProp = false;
972
973
  // Initialize all properties. We check whether the value of each property
974
  // will be overwritten (by comparing against what we have saved in propMap).
975
  // In that case we still compute the value (it could have side effects), but
976
  // we don't store it. The exception to this are accessor functions - there
977
  // is no need to create them if we don't use them because creating a function
978
  // has no side effects.
979
0
  for (auto &P : Expr->_properties) {
980
0
    if (auto *spread = llvh::dyn_cast<ESTree::SpreadElementNode>(&P)) {
981
0
      genBuiltinCall(
982
0
          BuiltinMethod::HermesBuiltin_copyDataProperties,
983
0
          {Obj, genExpression(spread->_argument)});
984
0
      haveSeenComputedProp = true;
985
0
      continue;
986
0
    }
987
988
    // We are reusing the storage, so make sure it is cleared at every
989
    // iteration.
990
0
    stringStorage.clear();
991
992
0
    auto *prop = cast<ESTree::PropertyNode>(&P);
993
994
0
    if (prop->_computed) {
995
      // TODO (T46136220): Set the .name property for anonymous functions that
996
      // are values for computed property keys.
997
0
      auto *key = genExpression(prop->_key);
998
0
      auto *value = genExpression(prop->_value);
999
0
      if (prop->_kind->str() == "get") {
1000
0
        Builder.createStoreGetterSetterInst(
1001
0
            value,
1002
0
            Builder.getLiteralUndefined(),
1003
0
            Obj,
1004
0
            key,
1005
0
            IRBuilder::PropEnumerable::Yes);
1006
0
      } else if (prop->_kind->str() == "set") {
1007
0
        Builder.createStoreGetterSetterInst(
1008
0
            Builder.getLiteralUndefined(),
1009
0
            value,
1010
0
            Obj,
1011
0
            key,
1012
0
            IRBuilder::PropEnumerable::Yes);
1013
0
      } else {
1014
0
        Builder.createStoreOwnPropertyInst(
1015
0
            value, Obj, key, IRBuilder::PropEnumerable::Yes);
1016
0
      }
1017
0
      haveSeenComputedProp = true;
1018
0
      continue;
1019
0
    }
1020
1021
0
    llvh::StringRef keyStr = propertyKeyAsString(stringStorage, prop->_key);
1022
1023
0
    if (prop == protoProperty) {
1024
      // This is the first definition of __proto__. If we already used it
1025
      // as an object parent we just skip it, but otherwise we must
1026
      // explicitly set the parent now by calling \c
1027
      // HermesInternal.silentSetPrototypeOf().
1028
0
      if (!objectParent) {
1029
0
        auto *parent = genExpression(prop->_value);
1030
1031
0
        IRBuilder::SaveRestore saveState{Builder};
1032
0
        Builder.setLocation(prop->_key->getDebugLoc());
1033
1034
0
        genBuiltinCall(
1035
0
            BuiltinMethod::HermesBuiltin_silentSetPrototypeOf, {Obj, parent});
1036
0
      }
1037
1038
0
      continue;
1039
0
    }
1040
1041
0
    PropertyValue *propValue = &propMap[keyStr];
1042
1043
    // For any node that has a corresponding propValue, we need to ensure that
1044
    // the we insert either a placeholder or the final IR before the end of this
1045
    // iteration.
1046
0
    auto checkState = llvh::make_scope_exit(
1047
0
        [&] { assert(propValue->state != PropertyValue::None); });
1048
1049
0
    auto *Key = Builder.getLiteralString(keyStr);
1050
1051
0
    auto maybeInsertPlaceholder = [&] {
1052
0
      if (propValue->state == PropertyValue::None) {
1053
        // This value is going to be overwritten, but insert a placeholder in
1054
        // order to maintain insertion order.
1055
0
        if (haveSeenComputedProp) {
1056
0
          Builder.createStoreOwnPropertyInst(
1057
0
              Builder.getLiteralNull(),
1058
0
              Obj,
1059
0
              Key,
1060
0
              IRBuilder::PropEnumerable::Yes);
1061
0
        } else {
1062
0
          Builder.createStoreNewOwnPropertyInst(
1063
0
              Builder.getLiteralNull(),
1064
0
              Obj,
1065
0
              Key,
1066
0
              IRBuilder::PropEnumerable::Yes);
1067
0
        }
1068
0
        propValue->state = PropertyValue::Placeholder;
1069
0
      }
1070
0
    };
1071
1072
0
    if (prop->_kind->str() == "get" || prop->_kind->str() == "set") {
1073
      // If  we already generated it, skip.
1074
0
      if (propValue->state == PropertyValue::IRGenerated)
1075
0
        continue;
1076
1077
0
      if (!propValue->isAccessor) {
1078
0
        maybeInsertPlaceholder();
1079
0
        continue;
1080
0
      }
1081
1082
0
      Value *getter = Builder.getLiteralUndefined();
1083
0
      Value *setter = Builder.getLiteralUndefined();
1084
1085
0
      if (propValue->getterNode) {
1086
0
        getter = genExpression(
1087
0
            propValue->getterNode,
1088
0
            Builder.createIdentifier("get " + keyStr.str()));
1089
0
      }
1090
1091
0
      if (propValue->setterNode) {
1092
0
        setter = genExpression(
1093
0
            propValue->setterNode,
1094
0
            Builder.createIdentifier("set " + keyStr.str()));
1095
0
      }
1096
1097
0
      Builder.createStoreGetterSetterInst(
1098
0
          getter, setter, Obj, Key, IRBuilder::PropEnumerable::Yes);
1099
1100
0
      propValue->state = PropertyValue::IRGenerated;
1101
1102
0
      continue;
1103
0
    }
1104
1105
    // Always generate the values, even if we don't need it, for the side
1106
    // effects.
1107
0
    auto value = genExpression(prop->_value, Builder.createIdentifier(keyStr));
1108
1109
    // Only store the value if it won't be overwritten.
1110
0
    if (propMap[keyStr].valueNode == prop->_value) {
1111
0
      assert(
1112
0
          propValue->state != PropertyValue::IRGenerated &&
1113
0
          "IR can only be generated once");
1114
0
      if (haveSeenComputedProp ||
1115
0
          propValue->state == PropertyValue::Placeholder) {
1116
0
        Builder.createStoreOwnPropertyInst(
1117
0
            value, Obj, Key, IRBuilder::PropEnumerable::Yes);
1118
0
      } else {
1119
0
        Builder.createStoreNewOwnPropertyInst(
1120
0
            value, Obj, Key, IRBuilder::PropEnumerable::Yes);
1121
0
      }
1122
0
      propValue->state = PropertyValue::IRGenerated;
1123
0
    } else {
1124
0
      maybeInsertPlaceholder();
1125
0
    }
1126
0
  }
1127
1128
  // Return the newly allocated object (because this is an expression, not a
1129
  // statement).
1130
0
  return Obj;
1131
0
}
1132
1133
251
Value *ESTreeIRGen::genSequenceExpr(ESTree::SequenceExpressionNode *Sq) {
1134
251
  Value *result = Builder.getLiteralUndefined();
1135
1136
  // Generate all expressions in the sequence, but take only the last one.
1137
544
  for (auto &Ex : Sq->_expressions) {
1138
544
    result = genExpression(&Ex);
1139
544
  }
1140
1141
251
  return result;
1142
251
}
1143
1144
0
Value *ESTreeIRGen::genYieldExpr(ESTree::YieldExpressionNode *Y) {
1145
0
  assert(!Y->_delegate && "must use genYieldStarExpr for yield*");
1146
1147
0
  Value *value = Y->_argument ? genExpression(Y->_argument)
1148
0
                              : Builder.getLiteralUndefined();
1149
0
  return genYieldOrAwaitExpr(value);
1150
0
}
1151
1152
0
Value *ESTreeIRGen::genAwaitExpr(ESTree::AwaitExpressionNode *A) {
1153
0
  Value *value = genExpression(A->_argument);
1154
0
  return genYieldOrAwaitExpr(value);
1155
0
}
1156
1157
0
Value *ESTreeIRGen::genYieldOrAwaitExpr(Value *value) {
1158
0
  auto *bb = Builder.getInsertionBlock();
1159
0
  auto *next = Builder.createBasicBlock(bb->getParent());
1160
1161
0
  auto *resumeIsReturn =
1162
0
      Builder.createAllocStackInst(genAnonymousLabelName("isReturn"));
1163
1164
0
  Builder.createSaveAndYieldInst(value, next);
1165
0
  Builder.setInsertionBlock(next);
1166
0
  return genResumeGenerator(
1167
0
      GenFinally::Yes,
1168
0
      resumeIsReturn,
1169
0
      Builder.createBasicBlock(bb->getParent()));
1170
0
}
1171
1172
/// Generate the code for `yield* value`.
1173
/// We use some stack locations to store state while iterating:
1174
/// - received (the value passed by the user to .next(), etc)
1175
/// - result (the final result of the yield* expression)
1176
///
1177
/// iteratorRecord stores the iterator which we are iterating over.
1178
///
1179
/// Final IR has the following basic blocks for normal control flow:
1180
///
1181
/// getNext: Get the next value from the iterator.
1182
/// - Call next() on the iteratorRecord and stores to `result`
1183
/// - If done, go to exit
1184
/// - Otherwise, go to body
1185
///
1186
/// resume: Runs the ResumeGenerator instruction.
1187
/// - Code for `finally` is also emitted here.
1188
///
1189
/// body: Yield the result of the next() call
1190
/// - Calls HermesInternal.generatorSetDelegated so that the result is not
1191
///   wrapped by the VM in an IterResult object.
1192
///
1193
/// exit: Returns `result` which should have the final results stored in it.
1194
///
1195
/// When the user calls `.return`, the finalizer is executed to call
1196
/// `iteratorRecord.return` if it exists. The code for that is contained within
1197
/// the SurroundingTry. If the .return function is defined, it is called and the
1198
/// 'done' property of the result of the call is used to either branch back to
1199
/// the 'resume' block or to propagate the return.
1200
///
1201
/// When the user calls '.throw', the code in emitHandler is executed. All
1202
/// generators used as delegates must have a .throw() method, so that is checked
1203
/// for and called. The result is then used to either resume if not done, or to
1204
/// return immediately by branching to the 'exit' block.
1205
0
Value *ESTreeIRGen::genYieldStarExpr(ESTree::YieldExpressionNode *Y) {
1206
0
  assert(Y->_delegate && "must use genYieldExpr for yield");
1207
0
  auto *function = Builder.getInsertionBlock()->getParent();
1208
0
  auto *getNextBlock = Builder.createBasicBlock(function);
1209
0
  auto *bodyBlock = Builder.createBasicBlock(function);
1210
0
  auto *exitBlock = Builder.createBasicBlock(function);
1211
1212
  // Calls ResumeGenerator and returns or throws if requested.
1213
0
  auto *resumeBB = Builder.createBasicBlock(function);
1214
1215
0
  auto *exprValue = genExpression(Y->_argument);
1216
0
  IteratorRecordSlow iteratorRecord = emitGetIteratorSlow(exprValue);
1217
1218
  // The "received" value when the user resumes the generator.
1219
  // Initialized to undefined on the first run, then stored to immediately
1220
  // following any genResumeGenerator.
1221
0
  auto *received =
1222
0
      Builder.createAllocStackInst(genAnonymousLabelName("received"));
1223
0
  Builder.createStoreStackInst(Builder.getLiteralUndefined(), received);
1224
1225
  // The "isReturn" value when the user resumes the generator.
1226
  // Stored to immediately following any genResumeGenerator.
1227
0
  auto *resumeIsReturn =
1228
0
      Builder.createAllocStackInst(genAnonymousLabelName("isReturn"));
1229
1230
  // The final result of the `yield*` expression.
1231
  // This can be set from either the body or the handler, so it is placed
1232
  // in the stack to allow populating it from anywhere.
1233
0
  auto *result = Builder.createAllocStackInst(genAnonymousLabelName("result"));
1234
1235
0
  Builder.createBranchInst(getNextBlock);
1236
1237
  // 7.a.i.  Let innerResult be ? Call(
1238
  //   iteratorRecord.[[NextMethod]],
1239
  //   iteratorRecord.[[Iterator]],
1240
  //   <received.[[Value]]>
1241
  // )
1242
  // Avoid using emitIteratorNext here because the spec does not.
1243
0
  Builder.setInsertionBlock(getNextBlock);
1244
0
  auto *nextResult = Builder.createCallInst(
1245
0
      CallInst::kNoTextifiedCallee,
1246
0
      iteratorRecord.nextMethod,
1247
0
      iteratorRecord.iterator,
1248
0
      {Builder.createLoadStackInst(received)});
1249
0
  emitEnsureObject(nextResult, "iterator.next() did not return an object");
1250
1251
0
  Builder.createStoreStackInst(nextResult, result);
1252
0
  auto *done = emitIteratorCompleteSlow(nextResult);
1253
0
  Builder.createCondBranchInst(done, exitBlock, bodyBlock);
1254
1255
0
  Builder.setInsertionBlock(bodyBlock);
1256
1257
0
  emitTryCatchScaffolding(
1258
0
      getNextBlock,
1259
      // emitBody.
1260
0
      [this,
1261
0
       Y,
1262
0
       resumeIsReturn,
1263
0
       getNextBlock,
1264
0
       resumeBB,
1265
0
       nextResult,
1266
0
       received,
1267
0
       &iteratorRecord]() {
1268
        // Generate IR for the body of Try
1269
0
        SurroundingTry thisTry{
1270
0
            curFunction(),
1271
0
            Y,
1272
0
            {},
1273
0
            [this, resumeBB, received, &iteratorRecord](
1274
0
                ESTree::Node *, ControlFlowChange cfc, BasicBlock *) {
1275
0
              if (cfc == ControlFlowChange::Break) {
1276
                // This finalizer block is executed upon early return during
1277
                // the yield*, which happens when the user requests a .return().
1278
0
                auto *function = Builder.getFunction();
1279
0
                auto *haveReturnBB = Builder.createBasicBlock(function);
1280
0
                auto *noReturnBB = Builder.createBasicBlock(function);
1281
0
                auto *isDoneBB = Builder.createBasicBlock(function);
1282
0
                auto *isNotDoneBB = Builder.createBasicBlock(function);
1283
1284
                // Check if "returnMethod" is undefined.
1285
0
                auto *returnMethod = genBuiltinCall(
1286
0
                    BuiltinMethod::HermesBuiltin_getMethod,
1287
0
                    {iteratorRecord.iterator,
1288
0
                     Builder.getLiteralString("return")});
1289
0
                Builder.createCompareBranchInst(
1290
0
                    returnMethod,
1291
0
                    Builder.getLiteralUndefined(),
1292
0
                    BinaryOperatorInst::OpKind::StrictlyEqualKind,
1293
0
                    noReturnBB,
1294
0
                    haveReturnBB);
1295
1296
0
                Builder.setInsertionBlock(haveReturnBB);
1297
                // iv. Let innerReturnResult be
1298
                // ? Call(return, iterator, received.[[Value]]).
1299
0
                auto *innerReturnResult = Builder.createCallInst(
1300
0
                    CallInst::kNoTextifiedCallee,
1301
0
                    returnMethod,
1302
0
                    iteratorRecord.iterator,
1303
0
                    {Builder.createLoadStackInst(received)});
1304
                // vi. If Type(innerReturnResult) is not Object,
1305
                // throw a TypeError exception.
1306
0
                emitEnsureObject(
1307
0
                    innerReturnResult,
1308
0
                    "iterator.return() did not return an object");
1309
                // vii. Let done be ? IteratorComplete(innerReturnResult).
1310
0
                auto *done = emitIteratorCompleteSlow(innerReturnResult);
1311
0
                Builder.createCondBranchInst(done, isDoneBB, isNotDoneBB);
1312
1313
0
                Builder.setInsertionBlock(isDoneBB);
1314
                // viii. 1. Let value be ? IteratorValue(innerReturnResult).
1315
0
                auto *value = emitIteratorValueSlow(innerReturnResult);
1316
0
                genFinallyBeforeControlChange(
1317
0
                    curFunction()->surroundingTry,
1318
0
                    nullptr,
1319
0
                    ControlFlowChange::Break);
1320
                // viii. 2. Return Completion
1321
                // { [[Type]]: return, [[Value]]: value, [[Target]]: empty }.
1322
0
                Builder.createReturnInst(value);
1323
1324
                // x. Else, set received to GeneratorYield(innerReturnResult).
1325
0
                Builder.setInsertionBlock(isNotDoneBB);
1326
0
                genBuiltinCall(
1327
0
                    BuiltinMethod::HermesBuiltin_generatorSetDelegated, {});
1328
0
                Builder.createSaveAndYieldInst(innerReturnResult, resumeBB);
1329
1330
                // If return is undefined, return Completion(received).
1331
0
                Builder.setInsertionBlock(noReturnBB);
1332
0
              }
1333
0
            }};
1334
1335
        // The primary call path for yielding the next result.
1336
0
        genBuiltinCall(BuiltinMethod::HermesBuiltin_generatorSetDelegated, {});
1337
0
        Builder.createSaveAndYieldInst(nextResult, resumeBB);
1338
1339
        // Note that resumeBB was created above to allow all SaveAndYield insts
1340
        // to have the same resume point (including SaveAndYield in the catch
1341
        // handler), but we must populate it inside the scaffolding so that the
1342
        // SurroundingTry is correct for the genFinallyBeforeControlChange
1343
        // call emitted by genResumeGenerator.
1344
0
        Builder.setInsertionBlock(resumeBB);
1345
0
        genResumeGenerator(
1346
0
            GenFinally::Yes, resumeIsReturn, getNextBlock, received);
1347
1348
        // SaveAndYieldInst is a Terminator, but emitTryCatchScaffolding
1349
        // needs a block from which to Branch to the TryEnd instruction.
1350
        // Make a dummy block which can do that.
1351
0
        Builder.setInsertionBlock(
1352
0
            Builder.createBasicBlock(Builder.getFunction()));
1353
0
      },
1354
      // emitNormalCleanup.
1355
0
      []() {},
1356
      // emitHandler.
1357
0
      [this, resumeBB, exitBlock, result, &iteratorRecord](
1358
0
          BasicBlock *getNextBlock) {
1359
0
        auto *catchReg = Builder.createCatchInst();
1360
1361
0
        auto *function = Builder.getFunction();
1362
0
        auto *hasThrowMethodBB = Builder.createBasicBlock(function);
1363
0
        auto *noThrowMethodBB = Builder.createBasicBlock(function);
1364
0
        auto *isDoneBB = Builder.createBasicBlock(function);
1365
0
        auto *isNotDoneBB = Builder.createBasicBlock(function);
1366
1367
        // b.i. Let throw be ? GetMethod(iterator, "throw").
1368
0
        auto *throwMethod = genBuiltinCall(
1369
0
            BuiltinMethod::HermesBuiltin_getMethod,
1370
0
            {iteratorRecord.iterator, Builder.getLiteralString("throw")});
1371
0
        Builder.createCompareBranchInst(
1372
0
            throwMethod,
1373
0
            Builder.getLiteralUndefined(),
1374
0
            BinaryOperatorInst::OpKind::StrictlyEqualKind,
1375
0
            noThrowMethodBB,
1376
0
            hasThrowMethodBB);
1377
1378
        // ii. If throw is not undefined, then
1379
0
        Builder.setInsertionBlock(hasThrowMethodBB);
1380
        // ii. 1. Let innerResult be
1381
        //        ? Call(throw, iterator, « received.[[Value]] »).
1382
        // ii. 3. NOTE: Exceptions from the inner iterator throw method are
1383
        // propagated. Normal completions from an inner throw method are
1384
        // processed similarly to an inner next.
1385
0
        auto *innerResult = Builder.createCallInst(
1386
0
            CallInst::kNoTextifiedCallee,
1387
0
            throwMethod,
1388
0
            iteratorRecord.iterator,
1389
0
            {catchReg});
1390
        // ii. 4. If Type(innerResult) is not Object,
1391
        //        throw a TypeError exception.
1392
0
        emitEnsureObject(
1393
0
            innerResult, "iterator.throw() did not return an object");
1394
        // ii. 5. Let done be ? IteratorComplete(innerResult).
1395
0
        auto *throwDone = emitIteratorCompleteSlow(innerResult);
1396
0
        Builder.createCondBranchInst(throwDone, isDoneBB, isNotDoneBB);
1397
1398
        // ii. 6. If done is true, then return ? IteratorValue(innerResult).
1399
0
        Builder.setInsertionBlock(isDoneBB);
1400
0
        Builder.createStoreStackInst(innerResult, result);
1401
0
        Builder.createBranchInst(exitBlock);
1402
1403
        // ii. 8. Else, set received to GeneratorYield(innerResult).
1404
0
        Builder.setInsertionBlock(isNotDoneBB);
1405
0
        genBuiltinCall(BuiltinMethod::HermesBuiltin_generatorSetDelegated, {});
1406
0
        Builder.createSaveAndYieldInst(innerResult, resumeBB);
1407
1408
        // NOTE: If iterator does not have a throw method, this throw is
1409
        // going to terminate the yield* loop. But first we need to give
1410
        // iterator a chance to clean up.
1411
0
        Builder.setInsertionBlock(noThrowMethodBB);
1412
0
        emitIteratorCloseSlow(iteratorRecord, false);
1413
0
        genBuiltinCall(
1414
0
            BuiltinMethod::HermesBuiltin_throwTypeError,
1415
0
            {Builder.getLiteralString(
1416
0
                "yield* delegate must have a .throw() method")});
1417
        // HermesInternal.throwTypeError will necessarily throw, but we need to
1418
        // have a terminator on this BB to allow proper optimization.
1419
0
        Builder.createThrowInst(Builder.getLiteralUndefined());
1420
0
      });
1421
1422
0
  Builder.setInsertionBlock(exitBlock);
1423
1424
0
  return emitIteratorValueSlow(Builder.createLoadStackInst(result));
1425
0
}
1426
1427
Value *ESTreeIRGen::genResumeGenerator(
1428
    GenFinally genFinally,
1429
    AllocStackInst *isReturn,
1430
    BasicBlock *nextBB,
1431
10
    AllocStackInst *received) {
1432
10
  auto *resume = Builder.createResumeGeneratorInst(isReturn);
1433
10
  if (received) {
1434
0
    Builder.createStoreStackInst(resume, received);
1435
0
  }
1436
10
  auto *retBB =
1437
10
      Builder.createBasicBlock(Builder.getInsertionBlock()->getParent());
1438
1439
10
  Builder.createCondBranchInst(
1440
10
      Builder.createLoadStackInst(isReturn), retBB, nextBB);
1441
1442
10
  Builder.setInsertionBlock(retBB);
1443
10
  if (received) {
1444
0
    Builder.createStoreStackInst(resume, received);
1445
0
  }
1446
10
  if (genFinally == GenFinally::Yes) {
1447
0
    genFinallyBeforeControlChange(
1448
0
        curFunction()->surroundingTry, nullptr, ControlFlowChange::Break);
1449
0
  }
1450
10
  Builder.createReturnInst(resume);
1451
1452
10
  Builder.setInsertionBlock(nextBB);
1453
10
  return resume;
1454
10
}
1455
1456
105k
Value *ESTreeIRGen::genBinaryExpression(ESTree::BinaryExpressionNode *bin) {
1457
  // Handle long chains of +/- non-recursively.
1458
105k
  if (bin->_operator->str() == "+" || bin->_operator->str() == "-") {
1459
24.8k
    auto list = linearizeLeft(bin, {"+", "-"});
1460
1461
24.8k
    Value *LHS = genExpression(list[0]->_left);
1462
172k
    for (auto *e : list) {
1463
172k
      Value *RHS = genExpression(e->_right);
1464
172k
      Builder.setLocation(e->getDebugLoc());
1465
172k
      auto cookie = instrumentIR_.preBinaryExpression(e, LHS, RHS);
1466
172k
      auto Kind = BinaryOperatorInst::parseOperator(e->_operator->str());
1467
172k
      BinaryOperatorInst *result =
1468
172k
          Builder.createBinaryOperatorInst(LHS, RHS, Kind);
1469
172k
      LHS = instrumentIR_.postBinaryExpression(e, cookie, result, LHS, RHS);
1470
172k
    }
1471
1472
24.8k
    return LHS;
1473
24.8k
  }
1474
1475
80.5k
  Value *LHS = genExpression(bin->_left);
1476
80.5k
  Value *RHS = genExpression(bin->_right);
1477
80.5k
  auto cookie = instrumentIR_.preBinaryExpression(bin, LHS, RHS);
1478
1479
80.5k
  auto Kind = BinaryOperatorInst::parseOperator(bin->_operator->str());
1480
1481
80.5k
  BinaryOperatorInst *result = Builder.createBinaryOperatorInst(LHS, RHS, Kind);
1482
80.5k
  return instrumentIR_.postBinaryExpression(bin, cookie, result, LHS, RHS);
1483
105k
}
1484
1485
64.2k
Value *ESTreeIRGen::genUnaryExpression(ESTree::UnaryExpressionNode *U) {
1486
64.2k
  auto kind = UnaryOperatorInst::parseOperator(U->_operator->str());
1487
1488
  // Handle the delete unary expression. https://es5.github.io/#x11.4.1
1489
64.2k
  if (kind == UnaryOperatorInst::OpKind::DeleteKind) {
1490
50.4k
    if (auto *memberExpr =
1491
50.4k
            llvh::dyn_cast<ESTree::MemberExpressionNode>(U->_argument)) {
1492
2
      LLVM_DEBUG(llvh::dbgs() << "IRGen delete member expression.\n");
1493
1494
2
      return genMemberExpression(memberExpr, MemberExpressionOperation::Delete)
1495
2
          .result;
1496
2
    }
1497
1498
50.4k
    if (auto *memberExpr = llvh::dyn_cast<ESTree::OptionalMemberExpressionNode>(
1499
50.4k
            U->_argument)) {
1500
0
      LLVM_DEBUG(llvh::dbgs() << "IRGen delete optional member expression.\n");
1501
1502
0
      return genOptionalMemberExpression(
1503
0
                 memberExpr, nullptr, MemberExpressionOperation::Delete)
1504
0
          .result;
1505
0
    }
1506
1507
    // Check for "delete identifier". Note that deleting unqualified identifiers
1508
    // is prohibited in strict mode, so that case is handled earlier in the
1509
    // semantic validator. Here we are left to handle the non-strict mode case.
1510
50.4k
    if (auto *iden = llvh::dyn_cast<ESTree::IdentifierNode>(U->_argument)) {
1511
50.0k
      assert(
1512
50.0k
          !curFunction()->function->isStrictMode() &&
1513
50.0k
          "delete identifier encountered in strict mode");
1514
      // Check if this is a known variable.
1515
50.0k
      Identifier name = getNameFieldFromID(iden);
1516
50.0k
      auto *var = nameTable_.lookup(name);
1517
1518
50.0k
      if (!var || llvh::isa<GlobalObjectProperty>(var)) {
1519
        // If the variable doesn't exist or if it is global, we must generate
1520
        // a delete global property instruction.
1521
22.3k
        return Builder.createDeletePropertyInst(
1522
22.3k
            Builder.getGlobalObject(), Builder.getLiteralString(name));
1523
27.7k
      } else {
1524
        // Otherwise it is a local variable which can't be deleted and we just
1525
        // return false.
1526
27.7k
        return Builder.getLiteralBool(false);
1527
27.7k
      }
1528
50.0k
    }
1529
1530
    // Generate the code for the delete operand.
1531
395
    genExpression(U->_argument);
1532
1533
    // Deleting any value or a result of an expression returns True.
1534
395
    return Builder.getLiteralBool(true);
1535
50.4k
  }
1536
1537
  // Need to handle the special case of "typeof <undefined variable>".
1538
13.8k
  if (kind == UnaryOperatorInst::OpKind::TypeofKind) {
1539
3
    if (auto *id = llvh::dyn_cast<ESTree::IdentifierNode>(U->_argument)) {
1540
0
      Value *argument = genIdentifierExpression(id, true);
1541
0
      return Builder.createUnaryOperatorInst(argument, kind);
1542
0
    }
1543
3
  }
1544
1545
  // Generate the unary operand:
1546
13.8k
  Value *argument = genExpression(U->_argument);
1547
13.8k
  auto *cookie = instrumentIR_.preUnaryExpression(U, argument);
1548
1549
13.8k
  Value *result;
1550
13.8k
  if (kind == UnaryOperatorInst::OpKind::PlusKind)
1551
298
    result = Builder.createAsNumberInst(argument);
1552
13.5k
  else
1553
13.5k
    result = Builder.createUnaryOperatorInst(argument, kind);
1554
13.8k
  return instrumentIR_.postUnaryExpression(U, cookie, result, argument);
1555
13.8k
}
1556
1557
0
Value *ESTreeIRGen::genUpdateExpr(ESTree::UpdateExpressionNode *updateExpr) {
1558
0
  LLVM_DEBUG(llvh::dbgs() << "IRGen update expression.\n");
1559
0
  bool isPrefix = updateExpr->_prefix;
1560
1561
0
  UnaryOperatorInst::OpKind opKind;
1562
0
  if (updateExpr->_operator->str() == "++") {
1563
0
    opKind = UnaryOperatorInst::OpKind::IncKind;
1564
0
  } else if (updateExpr->_operator->str() == "--") {
1565
0
    opKind = UnaryOperatorInst::OpKind::DecKind;
1566
0
  } else {
1567
0
    llvm_unreachable("Invalid update operator");
1568
0
  }
1569
1570
0
  LReference lref = createLRef(updateExpr->_argument, false);
1571
1572
  // Load the original value. Postfix updates need to convert it toNumeric
1573
  // before Inc/Dec to ensure the updateExpr has the proper result value.
1574
0
  Value *original =
1575
0
      isPrefix ? lref.emitLoad() : Builder.createAsNumericInst(lref.emitLoad());
1576
1577
  // Create the inc or dec.
1578
0
  Value *result = Builder.createUnaryOperatorInst(original, opKind);
1579
1580
  // Store the result.
1581
0
  lref.emitStore(result);
1582
1583
  // Depending on the prefixness return the previous value or the modified
1584
  // value.
1585
0
  return (isPrefix ? result : original);
1586
0
}
1587
1588
/// Extract a name hint from a LReference.
1589
1.98k
static Identifier extractNameHint(const LReference &lref) {
1590
1.98k
  Identifier nameHint{};
1591
1.98k
  if (auto *var = lref.castAsVariable()) {
1592
3
    nameHint = var->getName();
1593
1.98k
  } else if (auto *globProp = lref.castAsGlobalObjectProperty()) {
1594
1.52k
    nameHint = globProp->getName()->getValue();
1595
1.52k
  }
1596
1.98k
  return nameHint;
1597
1.98k
}
1598
1599
1.98k
Value *ESTreeIRGen::genAssignmentExpr(ESTree::AssignmentExpressionNode *AE) {
1600
1.98k
  LLVM_DEBUG(llvh::dbgs() << "IRGen assignment operator.\n");
1601
1602
1.98k
  auto opStr = AE->_operator->str();
1603
1604
  // Handle nested normal assignments non-recursively.
1605
1.98k
  if (opStr == "=") {
1606
1.97k
    auto list = ESTree::linearizeRight(AE, {"="});
1607
1608
    // Create an LReference for every assignment left side.
1609
1.97k
    llvh::SmallVector<LReference, 1> lrefs;
1610
1.97k
    lrefs.reserve(list.size());
1611
2.30k
    for (auto *e : list) {
1612
2.30k
      lrefs.push_back(createLRef(e->_left, false));
1613
2.30k
    }
1614
1615
1.97k
    Value *RHS = nullptr;
1616
1.97k
    auto lrefIterator = lrefs.end();
1617
2.30k
    for (auto *e : llvh::make_range(list.rbegin(), list.rend())) {
1618
2.30k
      --lrefIterator;
1619
2.30k
      if (!RHS)
1620
1.97k
        RHS = genExpression(e->_right, extractNameHint(*lrefIterator));
1621
2.30k
      Builder.setLocation(e->getDebugLoc());
1622
2.30k
      auto *cookie = instrumentIR_.preAssignment(e, nullptr, RHS);
1623
2.30k
      RHS = instrumentIR_.postAssignment(e, cookie, RHS, nullptr, RHS);
1624
2.30k
      lrefIterator->emitStore(RHS);
1625
2.30k
    }
1626
1627
1.97k
    return RHS;
1628
1.97k
  }
1629
1630
12
  auto AssignmentKind = BinaryOperatorInst::parseAssignmentOperator(opStr);
1631
1632
12
  LReference lref = createLRef(AE->_left, false);
1633
12
  Identifier nameHint = extractNameHint(lref);
1634
1635
12
  Value *result;
1636
12
  if (AssignmentKind == BinaryOperatorInst::OpKind::AssignShortCircuitOrKind ||
1637
12
      AssignmentKind == BinaryOperatorInst::OpKind::AssignShortCircuitAndKind ||
1638
12
      AssignmentKind == BinaryOperatorInst::OpKind::AssignNullishCoalesceKind) {
1639
8
    return genLogicalAssignmentExpr(AE, AssignmentKind, lref, nameHint);
1640
8
  }
1641
1642
4
  assert(AssignmentKind != BinaryOperatorInst::OpKind::IdentityKind);
1643
  // Section 11.13.1 specifies that we should first load the
1644
  // LHS before materializing the RHS. Unlike in C, this
1645
  // code is well defined: "x+= x++".
1646
  // https://es5.github.io/#x11.13.1
1647
4
  auto V = lref.emitLoad();
1648
4
  auto *RHS = genExpression(AE->_right, nameHint);
1649
4
  auto *cookie = instrumentIR_.preAssignment(AE, V, RHS);
1650
4
  result = Builder.createBinaryOperatorInst(V, RHS, AssignmentKind);
1651
4
  result = instrumentIR_.postAssignment(AE, cookie, result, V, RHS);
1652
1653
4
  lref.emitStore(result);
1654
1655
  // Return the value that we stored as the result of the expression.
1656
4
  return result;
1657
4
}
1658
1659
388
Value *ESTreeIRGen::genRegExpLiteral(ESTree::RegExpLiteralNode *RE) {
1660
388
  LLVM_DEBUG(llvh::dbgs() << "IRGen reg exp literal.\n");
1661
388
  LLVM_DEBUG(
1662
388
      llvh::dbgs() << "Loading regexp Literal \"" << RE->_pattern->str()
1663
388
                   << " / " << RE->_flags->str() << "\"\n");
1664
388
  auto exp = Builder.createRegExpInst(
1665
388
      Identifier::getFromPointer(RE->_pattern),
1666
388
      Identifier::getFromPointer(RE->_flags));
1667
1668
388
  auto &regexp = Builder.getModule()->getContext().getCompiledRegExp(
1669
388
      RE->_pattern, RE->_flags);
1670
1671
388
  if (regexp.getMapping().size()) {
1672
0
    auto &mapping = regexp.getMapping();
1673
0
    HBCAllocObjectFromBufferInst::ObjectPropertyMap propMap;
1674
0
    for (auto &identifier : regexp.getOrderedGroupNames()) {
1675
0
      std::string converted;
1676
0
      convertUTF16ToUTF8WithSingleSurrogates(converted, identifier);
1677
0
      auto *key = Builder.getLiteralString(converted);
1678
0
      auto groupIdxRes = mapping.find(identifier);
1679
0
      assert(
1680
0
          groupIdxRes != mapping.end() &&
1681
0
          "identifier not found in named groups");
1682
0
      auto groupIdx = groupIdxRes->second;
1683
0
      auto *val = Builder.getLiteralNumber(groupIdx);
1684
0
      propMap.emplace_back(key, val);
1685
0
    }
1686
0
    auto sz = mapping.size();
1687
1688
0
    auto literalObj = Builder.createHBCAllocObjectFromBufferInst(propMap, sz);
1689
1690
0
    Value *params[] = {exp, literalObj};
1691
0
    Builder.createCallBuiltinInst(
1692
0
        BuiltinMethod::HermesBuiltin_initRegexNamedGroups, params);
1693
0
  }
1694
1695
388
  return exp;
1696
388
}
1697
1698
Value *ESTreeIRGen::genLogicalAssignmentExpr(
1699
    ESTree::AssignmentExpressionNode *AE,
1700
    BinaryOperatorInst::OpKind AssignmentKind,
1701
    LReference lref,
1702
8
    Identifier nameHint) {
1703
  // Logical assignment expressions must use short-circuiting logic.
1704
  // BB which actually performs the assignment.
1705
8
  BasicBlock *assignBB = Builder.createBasicBlock(Builder.getFunction());
1706
  // BB which simply continues without performing the assignment.
1707
8
  BasicBlock *continueBB = Builder.createBasicBlock(Builder.getFunction());
1708
8
  auto *lhs = lref.emitLoad();
1709
1710
8
  PhiInst::ValueListType values;
1711
8
  PhiInst::BasicBlockListType blocks;
1712
1713
8
  values.push_back(lhs);
1714
8
  blocks.push_back(Builder.getInsertionBlock());
1715
1716
8
  switch (AssignmentKind) {
1717
8
    case BinaryOperatorInst::OpKind::AssignShortCircuitOrKind:
1718
8
      Builder.createCondBranchInst(lhs, continueBB, assignBB);
1719
8
      break;
1720
0
    case BinaryOperatorInst::OpKind::AssignShortCircuitAndKind:
1721
0
      Builder.createCondBranchInst(lhs, assignBB, continueBB);
1722
0
      break;
1723
0
    case BinaryOperatorInst::OpKind::AssignNullishCoalesceKind:
1724
0
      Builder.createCondBranchInst(
1725
0
          Builder.createBinaryOperatorInst(
1726
0
              lhs,
1727
0
              Builder.getLiteralNull(),
1728
0
              BinaryOperatorInst::OpKind::EqualKind),
1729
0
          assignBB,
1730
0
          continueBB);
1731
0
      break;
1732
0
    default:
1733
0
      llvm_unreachable("invalid AssignmentKind in this branch");
1734
8
  }
1735
1736
8
  Builder.setInsertionBlock(assignBB);
1737
8
  auto *rhs = genExpression(AE->_right, nameHint);
1738
8
  auto *cookie = instrumentIR_.preAssignment(AE, lhs, rhs);
1739
8
  auto *result = instrumentIR_.postAssignment(AE, cookie, rhs, lhs, rhs);
1740
8
  lref.emitStore(result);
1741
8
  values.push_back(result);
1742
8
  blocks.push_back(Builder.getInsertionBlock());
1743
8
  Builder.createBranchInst(continueBB);
1744
1745
8
  Builder.setInsertionBlock(continueBB);
1746
  // Final result is either the original value or the value assigned,
1747
  // depending on which branch was taken.
1748
8
  return Builder.createPhiInst(std::move(values), std::move(blocks));
1749
8
}
1750
1751
5.06k
Value *ESTreeIRGen::genConditionalExpr(ESTree::ConditionalExpressionNode *C) {
1752
5.06k
  auto parentFunc = Builder.getInsertionBlock()->getParent();
1753
1754
5.06k
  PhiInst::ValueListType values;
1755
5.06k
  PhiInst::BasicBlockListType blocks;
1756
1757
5.06k
  auto alternateBlock = Builder.createBasicBlock(parentFunc);
1758
5.06k
  auto consequentBlock = Builder.createBasicBlock(parentFunc);
1759
5.06k
  auto continueBlock = Builder.createBasicBlock(parentFunc);
1760
1761
  // Implement the ternary operator using control flow. We must use control
1762
  // flow because the expressions may have side effects.
1763
5.06k
  genExpressionBranch(C->_test, consequentBlock, alternateBlock, nullptr);
1764
1765
  // The 'then' side:
1766
5.06k
  Builder.setInsertionBlock(consequentBlock);
1767
1768
5.06k
  values.push_back(genExpression(C->_consequent));
1769
5.06k
  blocks.push_back(Builder.getInsertionBlock());
1770
5.06k
  Builder.createBranchInst(continueBlock);
1771
1772
  // The 'else' side:
1773
5.06k
  Builder.setInsertionBlock(alternateBlock);
1774
5.06k
  values.push_back(genExpression(C->_alternate));
1775
5.06k
  blocks.push_back(Builder.getInsertionBlock());
1776
5.06k
  Builder.createBranchInst(continueBlock);
1777
1778
  // Continue:
1779
5.06k
  Builder.setInsertionBlock(continueBlock);
1780
5.06k
  return Builder.createPhiInst(values, blocks);
1781
5.06k
}
1782
1783
Value *ESTreeIRGen::genIdentifierExpression(
1784
    ESTree::IdentifierNode *Iden,
1785
439k
    bool afterTypeOf) {
1786
439k
  LLVM_DEBUG(
1787
439k
      llvh::dbgs() << "Looking for identifier \"" << Iden->_name << "\"\n");
1788
1789
  // 'arguments' is an array-like object holding all function arguments.
1790
  // If one of the parameters is called "arguments" then it shadows the
1791
  // arguments keyword.
1792
439k
  if (Iden->_name->str() == "arguments" &&
1793
439k
      !nameTable_.count(getNameFieldFromID(Iden))) {
1794
    // If it is captured, we must use the captured value.
1795
52
    if (curFunction()->capturedArguments) {
1796
0
      return Builder.createLoadFrameInst(
1797
0
          curFunction()->capturedArguments, currentIRScope_);
1798
0
    }
1799
1800
52
    return curFunction()->createArgumentsInst;
1801
52
  }
1802
1803
  // Lookup variable name.
1804
439k
  auto StrName = getNameFieldFromID(Iden);
1805
1806
439k
  auto *Var = ensureVariableExists(Iden);
1807
1808
  // For uses of undefined as the global property, we make an optimization
1809
  // to always return undefined constant.
1810
439k
  if (llvh::isa<GlobalObjectProperty>(Var) && StrName.str() == "undefined") {
1811
0
    return Builder.getLiteralUndefined();
1812
0
  }
1813
1814
439k
  LLVM_DEBUG(
1815
439k
      llvh::dbgs() << "Found variable " << StrName << " in function \""
1816
439k
                   << (llvh::isa<GlobalObjectProperty>(Var)
1817
439k
                           ? llvh::StringRef("global")
1818
439k
                           : cast<Variable>(Var)
1819
439k
                                 ->getParent()
1820
439k
                                 ->getFunction()
1821
439k
                                 ->getInternalNameStr())
1822
439k
                   << "\"\n");
1823
1824
  // Typeof <variable> does not throw.
1825
439k
  return emitLoad(Var, afterTypeOf);
1826
439k
}
1827
1828
0
Value *ESTreeIRGen::genMetaProperty(ESTree::MetaPropertyNode *MP) {
1829
  // Recognize "new.target"
1830
0
  if (cast<ESTree::IdentifierNode>(MP->_meta)->_name->str() == "new") {
1831
0
    if (cast<ESTree::IdentifierNode>(MP->_property)->_name->str() == "target") {
1832
0
      Value *value;
1833
1834
0
      if (curFunction()->function->getDefinitionKind() ==
1835
0
              Function::DefinitionKind::ES6Arrow ||
1836
0
          curFunction()->function->getDefinitionKind() ==
1837
0
              Function::DefinitionKind::ES6Method) {
1838
0
        value = curFunction()->capturedNewTarget;
1839
0
      } else {
1840
0
        value = Builder.createGetNewTargetInst();
1841
0
      }
1842
1843
      // If it is a variable, we must issue a load.
1844
0
      if (auto *V = llvh::dyn_cast<Variable>(value))
1845
0
        return Builder.createLoadFrameInst(V, currentIRScope_);
1846
1847
0
      return value;
1848
0
    }
1849
0
  }
1850
1851
0
  llvm_unreachable("invalid MetaProperty");
1852
0
}
1853
1854
50
Value *ESTreeIRGen::genNewExpr(ESTree::NewExpressionNode *N) {
1855
50
  LLVM_DEBUG(llvh::dbgs() << "IRGen 'new' statement/expression.\n");
1856
1857
50
  Value *callee = genExpression(N->_callee);
1858
1859
50
  bool hasSpread = false;
1860
50
  for (auto &arg : N->_arguments) {
1861
1
    if (llvh::isa<ESTree::SpreadElementNode>(&arg)) {
1862
1
      hasSpread = true;
1863
1
    }
1864
1
  }
1865
1866
50
  if (!hasSpread) {
1867
49
    ConstructInst::ArgumentList args;
1868
49
    for (auto &arg : N->_arguments) {
1869
0
      args.push_back(genExpression(&arg));
1870
0
    }
1871
1872
49
    return Builder.createConstructInst(callee, callee, args);
1873
49
  }
1874
1875
  // Otherwise, there exists a spread argument, so the number of arguments
1876
  // is variable.
1877
  // Generate IR for this by creating an array and populating it with the
1878
  // arguments, then calling HermesInternal.apply.
1879
1
  auto *args = genArrayFromElements(N->_arguments);
1880
1881
1
  return genBuiltinCall(BuiltinMethod::HermesBuiltin_apply, {callee, args});
1882
50
}
1883
1884
Value *ESTreeIRGen::genLogicalExpression(
1885
2.00k
    ESTree::LogicalExpressionNode *logical) {
1886
2.00k
  auto opStr = logical->_operator->str();
1887
2.00k
  LLVM_DEBUG(llvh::dbgs() << "IRGen of short circuiting: " << opStr << ".\n");
1888
1889
2.00k
  enum class Kind {
1890
2.00k
    And, // &&
1891
2.00k
    Or, // ||
1892
2.00k
    Coalesce, // ??
1893
2.00k
  };
1894
1895
2.00k
  Kind kind;
1896
1897
2.00k
  if (opStr == "&&") {
1898
10
    kind = Kind::And;
1899
1.99k
  } else if (opStr == "||") {
1900
1.85k
    kind = Kind::Or;
1901
1.85k
  } else if (opStr == "??") {
1902
142
    kind = Kind::Coalesce;
1903
142
  } else {
1904
0
    llvm_unreachable("Invalid update operator");
1905
0
  }
1906
1907
  // Generate a new temporary stack allocation.
1908
2.00k
  auto tempVarName = genAnonymousLabelName("logical");
1909
2.00k
  auto parentFunc = Builder.getInsertionBlock()->getParent();
1910
2.00k
  auto tempVar = Builder.createAllocStackInst(tempVarName);
1911
1912
2.00k
  auto evalRHSBlock = Builder.createBasicBlock(parentFunc);
1913
2.00k
  auto continueBlock = Builder.createBasicBlock(parentFunc);
1914
1915
2.00k
  auto LHS = genExpression(logical->_left);
1916
1917
  // Store the LHS value of the expression in preparation for the case where we
1918
  // won't need to evaluate the RHS side of the expression. In that case, we
1919
  // jump to continueBlock, which returns tempVar.
1920
2.00k
  Builder.createStoreStackInst(LHS, tempVar);
1921
1922
  // Notice that instead of negating the condition we swap the operands of the
1923
  // branch.
1924
2.00k
  switch (kind) {
1925
10
    case Kind::And:
1926
      // Evaluate RHS only when the LHS is true.
1927
10
      Builder.createCondBranchInst(LHS, evalRHSBlock, continueBlock);
1928
10
      break;
1929
1.85k
    case Kind::Or:
1930
      // Evaluate RHS only when the LHS is false.
1931
1.85k
      Builder.createCondBranchInst(LHS, continueBlock, evalRHSBlock);
1932
1.85k
      break;
1933
142
    case Kind::Coalesce:
1934
      // Evaluate RHS only if the value is undefined or null.
1935
      // Use == instead of === to account for both values at once.
1936
142
      Builder.createCondBranchInst(
1937
142
          Builder.createBinaryOperatorInst(
1938
142
              LHS,
1939
142
              Builder.getLiteralNull(),
1940
142
              BinaryOperatorInst::OpKind::EqualKind),
1941
142
          evalRHSBlock,
1942
142
          continueBlock);
1943
1944
142
      break;
1945
2.00k
  }
1946
1947
  // Continue the evaluation of the right-hand-side of the expression.
1948
2.00k
  Builder.setInsertionBlock(evalRHSBlock);
1949
2.00k
  auto RHS = genExpression(logical->_right);
1950
1951
  // Evaluate the RHS and store the result into the temporary variable.
1952
2.00k
  Builder.createStoreStackInst(RHS, tempVar);
1953
1954
  // Finally, jump to the continuation block.
1955
2.00k
  Builder.createBranchInst(continueBlock);
1956
1957
  // Load the content of the temp variable that was set in one of the branches.
1958
2.00k
  Builder.setInsertionBlock(continueBlock);
1959
2.00k
  return Builder.createLoadStackInst(tempVar);
1960
2.00k
}
1961
1962
void ESTreeIRGen::genLogicalExpressionBranch(
1963
    ESTree::LogicalExpressionNode *logical,
1964
    BasicBlock *onTrue,
1965
    BasicBlock *onFalse,
1966
0
    BasicBlock *onNullish) {
1967
0
  auto opStr = logical->_operator->str();
1968
0
  LLVM_DEBUG(
1969
0
      llvh::dbgs() << "IRGen of short circuiting: " << opStr << " branch.\n");
1970
1971
0
  auto parentFunc = Builder.getInsertionBlock()->getParent();
1972
0
  auto *block = Builder.createBasicBlock(parentFunc);
1973
1974
0
  if (opStr == "&&") {
1975
0
    genExpressionBranch(logical->_left, block, onFalse, onNullish);
1976
0
  } else if (opStr == "||") {
1977
0
    genExpressionBranch(logical->_left, onTrue, block, onNullish);
1978
0
  } else {
1979
0
    assert(opStr == "??" && "invalid logical operator");
1980
0
    genExpressionBranch(logical->_left, onTrue, onFalse, block);
1981
0
  }
1982
1983
0
  Builder.setInsertionBlock(block);
1984
0
  genExpressionBranch(logical->_right, onTrue, onFalse, onNullish);
1985
0
}
1986
1987
40.3k
Value *ESTreeIRGen::genTemplateLiteralExpr(ESTree::TemplateLiteralNode *Expr) {
1988
40.3k
  LLVM_DEBUG(llvh::dbgs() << "IRGen 'TemplateLiteral' expression.\n");
1989
1990
40.3k
  assert(
1991
40.3k
      Expr->_quasis.size() == Expr->_expressions.size() + 1 &&
1992
40.3k
      "The string count should always be one more than substitution count.");
1993
1994
  // Construct an argument list for calling HermesInternal.concat():
1995
  // cookedStr0, substitution0, cookedStr1, ..., substitutionN, cookedStrN + 1,
1996
  // skipping any empty string, except for the first cooked string, which is
1997
  // going to be the `this` to the concat call.
1998
1999
  // Get the first cooked string.
2000
40.3k
  auto strItr = Expr->_quasis.begin();
2001
40.3k
  auto *tempEltNode = cast<ESTree::TemplateElementNode>(&*strItr);
2002
40.3k
  auto *firstCookedStr = Builder.getLiteralString(tempEltNode->_cooked->str());
2003
40.3k
  ++strItr;
2004
  // If the template literal is effectively only one string, directly return it.
2005
40.3k
  if (strItr == Expr->_quasis.end()) {
2006
40.3k
    return firstCookedStr;
2007
40.3k
  }
2008
0
  CallInst::ArgumentList argList;
2009
0
  auto exprItr = Expr->_expressions.begin();
2010
0
  while (strItr != Expr->_quasis.end()) {
2011
0
    auto *sub = genExpression(&*exprItr);
2012
0
    argList.push_back(sub);
2013
0
    tempEltNode = cast<ESTree::TemplateElementNode>(&*strItr);
2014
0
    auto cookedStr = tempEltNode->_cooked->str();
2015
0
    if (!cookedStr.empty()) {
2016
0
      argList.push_back(Builder.getLiteralString(cookedStr));
2017
0
    }
2018
0
    ++strItr;
2019
0
    ++exprItr;
2020
0
  }
2021
0
  assert(
2022
0
      exprItr == Expr->_expressions.end() &&
2023
0
      "All the substitutions must have been collected.");
2024
2025
  // Generate a function call to HermesInternal.concat() with these arguments.
2026
0
  return genHermesInternalCall("concat", firstCookedStr, argList);
2027
0
}
2028
2029
Value *ESTreeIRGen::genTaggedTemplateExpr(
2030
5.00k
    ESTree::TaggedTemplateExpressionNode *Expr) {
2031
5.00k
  LLVM_DEBUG(llvh::dbgs() << "IRGen 'TaggedTemplateExpression' expression.\n");
2032
  // Step 1: get the template object.
2033
5.00k
  auto *templateLit = cast<ESTree::TemplateLiteralNode>(Expr->_quasi);
2034
2035
  // Construct an argument list for calling HermesInternal.getTemplateObject():
2036
  // [template object ID, dup, raw strings, (optional) cooked strings].
2037
5.00k
  CallInst::ArgumentList argList;
2038
  // Retrieve template object ID.
2039
5.00k
  Module::RawStringList rawStrings;
2040
116k
  for (auto &n : templateLit->_quasis) {
2041
116k
    auto element = cast<ESTree::TemplateElementNode>(&n);
2042
116k
    rawStrings.push_back(Builder.getLiteralString(element->_raw->str()));
2043
116k
  }
2044
5.00k
  uint32_t templateObjID = Mod->getTemplateObjectID(std::move(rawStrings));
2045
5.00k
  argList.push_back(Builder.getLiteralNumber(templateObjID));
2046
2047
  // dup is true if the cooked strings and raw strings are duplicated.
2048
5.00k
  bool dup = true;
2049
  // Add the argument dup first as a placeholder which we overwrite with
2050
  // the correct value later.
2051
5.00k
  argList.push_back(Builder.getLiteralBool(dup));
2052
116k
  for (auto &node : templateLit->_quasis) {
2053
116k
    auto *templateElt = cast<ESTree::TemplateElementNode>(&node);
2054
116k
    if (templateElt->_cooked != templateElt->_raw) {
2055
1.10k
      dup = false;
2056
1.10k
    }
2057
116k
    argList.push_back(Builder.getLiteralString(templateElt->_raw->str()));
2058
116k
  }
2059
5.00k
  argList[1] = Builder.getLiteralBool(dup);
2060
  // If the cooked strings are not the same as raw strings, append them to
2061
  // argument list.
2062
5.00k
  if (!dup) {
2063
1.11k
    for (auto &node : templateLit->_quasis) {
2064
1.11k
      auto *templateElt = cast<ESTree::TemplateElementNode>(&node);
2065
1.11k
      if (templateElt->_cooked) {
2066
851
        argList.push_back(
2067
851
            Builder.getLiteralString(templateElt->_cooked->str()));
2068
851
      } else {
2069
259
        argList.push_back(Builder.getLiteralUndefined());
2070
259
      }
2071
1.11k
    }
2072
1.10k
  }
2073
2074
  // Generate a function call to HermesInternal.getTemplateObject() with these
2075
  // arguments.
2076
5.00k
  auto *templateObj =
2077
5.00k
      genBuiltinCall(BuiltinMethod::HermesBuiltin_getTemplateObject, argList);
2078
2079
  // Step 2: call the tag function, passing the template object followed by a
2080
  // list of substitutions as arguments.
2081
5.00k
  CallInst::ArgumentList tagFuncArgList;
2082
5.00k
  tagFuncArgList.push_back(templateObj);
2083
111k
  for (auto &sub : templateLit->_expressions) {
2084
111k
    tagFuncArgList.push_back(genExpression(&sub));
2085
111k
  }
2086
2087
5.00k
  Value *callee;
2088
5.00k
  Value *thisVal;
2089
  // Tag function is a member expression.
2090
5.00k
  if (auto *Mem = llvh::dyn_cast<ESTree::MemberExpressionNode>(Expr->_tag)) {
2091
31
    Value *obj = genExpression(Mem->_object);
2092
31
    Value *prop = genMemberExpressionProperty(Mem);
2093
    // Call the callee with obj as the 'this'.
2094
31
    thisVal = obj;
2095
31
    callee = Builder.createLoadPropertyInst(obj, prop);
2096
4.97k
  } else {
2097
4.97k
    thisVal = Builder.getLiteralUndefined();
2098
4.97k
    callee = genExpression(Expr->_tag);
2099
4.97k
  }
2100
2101
5.00k
  return Builder.createCallInst(
2102
5.00k
      CallInst::kNoTextifiedCallee, callee, thisVal, tagFuncArgList);
2103
5.00k
}
2104
2105
} // namespace irgen
2106
} // namespace hermes