Coverage Report

Created: 2025-12-11 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hermes/lib/IR/IR.cpp
Line
Count
Source
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 "llvh/ADT/SetVector.h"
9
#include "llvh/ADT/SmallString.h"
10
#include "llvh/Support/Casting.h"
11
#include "llvh/Support/ErrorHandling.h"
12
#include "llvh/Support/raw_ostream.h"
13
14
#include "hermes/AST/Context.h"
15
#include "hermes/IR/IR.h"
16
#include "hermes/IR/Instrs.h"
17
#include "hermes/Utils/Dumper.h"
18
19
#include <set>
20
#include <type_traits>
21
22
#define INCLUDE_ALL_INSTRS
23
24
using namespace hermes;
25
26
// Make sure the ValueKinds.def tree is consistent with the class hierarchy.
27
#define QUOTE(X) #X
28
#define DEF_VALUE(CLASS, PARENT)                                           \
29
  static_assert(                                                           \
30
      std::is_base_of<PARENT, CLASS>::value,                               \
31
      QUOTE(CLASS) " should directly inherit from " QUOTE(PARENT));        \
32
  static_assert(                                                           \
33
      std::is_convertible<CLASS *, PARENT *>::value,                       \
34
      QUOTE(CLASS) " should publicly inherit from " QUOTE(PARENT));        \
35
  static_assert(                                                           \
36
      ValueKind::CLASS##Kind > ValueKind::First_##PARENT##Kind,            \
37
      QUOTE(CLASS) "Kind should be after First_" QUOTE(PARENT) "Kind");    \
38
  static_assert(                                                           \
39
      ValueKind::CLASS##Kind < ValueKind::Last_##PARENT##Kind,             \
40
      QUOTE(CLASS) "Kind should be before Last_" QUOTE(PARENT) "Kind");    \
41
  static_assert(                                                           \
42
      ValueKind::PARENT##Kind ==                                           \
43
          static_cast<ValueKind>(                                          \
44
              static_cast<unsigned>(ValueKind::First_##PARENT##Kind) + 1), \
45
      QUOTE(PARENT) "Kind should be right after First_" QUOTE(PARENT) "Kind");
46
#include "hermes/IR/ValueKinds.def"
47
#undef QUOTE
48
49
4.22M
void Value::destroy(Value *V) {
50
4.22M
  if (!V)
51
80
    return;
52
53
4.22M
  switch (V->Kind) {
54
0
    default:
55
0
      llvm_unreachable("Invalid kind");
56
0
#define DEF_VALUE(XX, PARENT) \
57
4.22M
  case ValueKind::XX##Kind:   \
58
4.22M
    delete cast<XX>(V);       \
59
4.22M
    break;
60
4.22M
#include "hermes/IR/ValueKinds.def"
61
4.22M
  }
62
4.22M
}
63
64
0
llvh::StringRef Value::getKindStr() const {
65
0
  switch (Kind) {
66
0
    default:
67
0
      llvm_unreachable("Invalid kind");
68
0
#define DEF_VALUE(XX, PARENT) \
69
0
  case ValueKind::XX##Kind:   \
70
0
    return llvh::StringRef(#XX);
71
0
#include "hermes/IR/ValueKinds.def"
72
0
  }
73
0
}
74
75
6.04k
const Value::UseListTy &Value::getUsers() const {
76
6.04k
  return Users;
77
6.04k
}
78
79
0
unsigned Value::getNumUsers() const {
80
0
  return Users.size();
81
0
}
82
83
3.93k
bool Value::hasUsers() const {
84
3.93k
  return Users.size();
85
3.93k
}
86
87
0
bool Value::hasOneUser() const {
88
0
  return 1 == Users.size();
89
0
}
90
91
3.97M
void Value::removeUse(Use U) {
92
3.97M
  assert(Users.size() && "Removing a user from an empty list");
93
3.97M
  assert(U.first == this && "Invalid user");
94
95
  // We don't care about the order of the operands in the use vector. One cheap
96
  // way to delete an element is to pop the last element and save it on top of
97
  // the element that we want to remove. This is faster than moving the whole
98
  // array.
99
3.97M
  Users[U.second] = Users.back();
100
3.97M
  Users.pop_back();
101
102
  // If we've changed the location of a use in the use list then we need to
103
  // update the operand in the user.
104
3.97M
  if (U.second != Users.size()) {
105
2.53M
    Use oldUse = {this, static_cast<unsigned>(Users.size())};
106
2.53M
    auto &operands = Users[U.second]->Operands;
107
2.82M
    for (int i = 0, e = operands.size(); i < e; i++) {
108
2.82M
      if (operands[i] == oldUse) {
109
2.53M
        operands[i] = {this, U.second};
110
2.53M
        return;
111
2.53M
      }
112
2.82M
    }
113
2.53M
    llvm_unreachable("Can't find user in operand list");
114
2.53M
  }
115
3.97M
}
116
117
9.32M
Value::Use Value::addUser(Instruction *Inst) {
118
9.32M
  Users.push_back(Inst);
119
9.32M
  return {this, static_cast<unsigned>(Users.size() - 1)};
120
9.32M
}
121
122
843k
void Value::replaceAllUsesWith(Value *Other) {
123
843k
  if (this == Other) {
124
0
    return;
125
0
  }
126
127
  // Ask the users of this value to unregister themselves. Notice that the users
128
  // modify and invalidate the iterators of Users.
129
2.11M
  while (Users.size()) {
130
1.26M
    Users[Users.size() - 1]->replaceFirstOperandWith(this, Other);
131
1.26M
  }
132
843k
}
133
134
0
void Value::removeAllUses() {
135
  // Ask the users of this value to delete operands of this value. Notice that
136
  // the users modify and invalidate the iterators of Users.
137
0
  while (Users.size()) {
138
0
    Users[Users.size() - 1]->eraseOperand(this);
139
0
  }
140
0
}
141
142
0
bool Value::hasUser(Value *other) {
143
0
  return std::find(Users.begin(), Users.end(), other) != Users.end();
144
0
}
145
146
2.13k
ScopeDesc::~ScopeDesc() {
147
2.13k
  for (ScopeDesc *inner : innerScopes_) {
148
1.99k
    Value::destroy(inner);
149
1.99k
  }
150
151
  // Free all variables.
152
2.13k
  for (auto *v : variables_) {
153
1.80k
    Value::destroy(v);
154
1.80k
  }
155
2.13k
}
156
157
5
bool ScopeDesc::isGlobalScope() const {
158
5
  return function_->isGlobalScope() &&
159
5
      function_->getFunctionScopeDesc() == this;
160
5
}
161
162
Function::Function(
163
    ValueKind kind,
164
    Module *parent,
165
    ScopeDesc *scopeDesc,
166
    Identifier originalName,
167
    DefinitionKind definitionKind,
168
    bool strictMode,
169
    SourceVisibility sourceVisibility,
170
    bool isGlobal,
171
    SMRange sourceRange,
172
    Function *insertBefore)
173
1.99k
    : Value(kind),
174
1.99k
      parent_(parent),
175
1.99k
      isGlobal_(isGlobal),
176
1.99k
      scopeDesc_(scopeDesc),
177
1.99k
      originalOrInferredName_(originalName),
178
1.99k
      definitionKind_(definitionKind),
179
1.99k
      strictMode_(strictMode),
180
1.99k
      SourceRange(sourceRange),
181
1.99k
      sourceVisibility_(sourceVisibility),
182
1.99k
      internalName_(parent->deriveUniqueInternalName(originalName)) {
183
1.99k
  scopeDesc_->setFunction(this);
184
1.99k
  if (insertBefore) {
185
0
    assert(insertBefore != this && "Cannot insert a function before itself!");
186
0
    assert(
187
0
        insertBefore->getParent() == parent &&
188
0
        "Function to insert before is from a different module!");
189
0
    parent->insert(insertBefore->getIterator(), this);
190
1.99k
  } else {
191
1.99k
    parent->push_back(this);
192
1.99k
  }
193
194
  // Derive internalName from originalName.
195
1.99k
  assert(originalName.isValid() && "Function originalName must be valid");
196
1.99k
}
197
198
1.99k
Function::~Function() {
199
  // Free all parameters.
200
1.99k
  for (auto *p : Parameters) {
201
1.78k
    Value::destroy(p);
202
1.78k
  }
203
1.99k
  Value::destroy(thisParameter);
204
1.99k
}
205
206
0
std::string Function::getDefinitionKindStr(bool isDescriptive) const {
207
0
  switch (definitionKind_) {
208
0
    case Function::DefinitionKind::ES5Function:
209
0
      return "function";
210
0
    case Function::DefinitionKind::ES6Constructor:
211
0
      return "constructor";
212
0
    case Function::DefinitionKind::ES6Arrow:
213
0
      return isDescriptive ? "arrow function" : "arrow";
214
0
    case Function::DefinitionKind::ES6Method:
215
0
      return "method";
216
0
  }
217
0
  assert(false && "Invalid DefinitionKind");
218
0
  return "function";
219
0
}
220
221
0
std::string Function::getDescriptiveDefinitionKindStr() const {
222
0
  return (isAnonymous() ? "anonymous " : "") + getDefinitionKindStr(true);
223
0
}
224
225
3.72k
llvh::Optional<llvh::StringRef> Function::getSourceRepresentationStr() const {
226
3.72k
  switch (getSourceVisibility()) {
227
0
    case SourceVisibility::ShowSource: {
228
      // Return the actual source code string.
229
0
      auto sourceRange = getSourceRange();
230
0
      assert(
231
0
          sourceRange.isValid() && "Function does not have source available");
232
0
      const auto sourceStart = sourceRange.Start.getPointer();
233
0
      llvh::StringRef strBuf{
234
0
          sourceStart, (size_t)(sourceRange.End.getPointer() - sourceStart)};
235
0
      return strBuf;
236
0
    }
237
0
    case SourceVisibility::HideSource:
238
0
    case SourceVisibility::Sensitive: {
239
      // For implementation-hiding functions, the spec requires the source code
240
      // representation of them "must have the syntax of a NativeFunction".
241
      //
242
      // Naively adding 'function <name>() { [ native code ] }' to string table
243
      // for each function would be a huge waste of space in the generated hbc.
244
      // Instead, we associate all such functions with an empty string to
245
      // effectively "mark" them. (the assumption is that an real function
246
      // source can't be empty). This reduced the constant factor of the space
247
      // cost to only 8 bytes (one FunctionSourceTable entry) per function.
248
0
      return llvh::StringRef("");
249
0
    }
250
3.72k
    case SourceVisibility::Default:
251
3.72k
    default: {
252
      // No need of special source representation for these cases, their
253
      // 'toString' will return `{ [ bytecode ] }` as the default.
254
3.72k
      return llvh::None;
255
3.72k
    }
256
3.72k
  }
257
3.72k
}
258
259
BasicBlock::BasicBlock(Function *parent)
260
62.5k
    : Value(ValueKind::BasicBlockKind), Parent(parent) {
261
62.5k
  assert(Parent && "Invalid parent function");
262
62.5k
  Parent->addBlock(this);
263
62.5k
}
264
265
0
void BasicBlock::dump(llvh::raw_ostream &os) const {
266
0
  IRPrinter D(getParent()->getContext(), os);
267
0
  D.visit(*this);
268
0
}
269
270
0
void BasicBlock::printAsOperand(llvh::raw_ostream &OS, bool) const {
271
  // Use the address of the basic block when LLVM prints the CFG.
272
0
  size_t Num = (size_t)this;
273
0
  OS << "BB#" << std::to_string(Num);
274
0
}
275
276
0
void Instruction::dump(llvh::raw_ostream &os) const {
277
0
  IRPrinter D(getParent()->getContext(), os);
278
0
  D.visit(*this);
279
0
}
280
281
Instruction::Instruction(
282
    const Instruction *src,
283
    llvh::ArrayRef<Value *> operands)
284
0
    : Instruction(src->getKind()) {
285
0
  assert(
286
0
      src->getNumOperands() == operands.size() && "invalid number of operands");
287
288
0
  setType(src->getType());
289
290
0
  location_ = src->location_;
291
0
  statementIndex_ = src->statementIndex_;
292
293
0
  for (auto val : operands)
294
0
    pushOperand(val);
295
0
}
296
297
5.79M
void Instruction::pushOperand(Value *Val) {
298
5.79M
  Operands.push_back({nullptr, 0});
299
5.79M
  setOperand(Val, getNumOperands() - 1);
300
5.79M
}
301
302
9.78M
void Instruction::setOperand(Value *Val, unsigned Index) {
303
9.78M
  assert(Index < Operands.size() && "Not all operands have been pushed!");
304
305
9.78M
  Value *CurrentValue = Operands[Index].first;
306
307
  // If the operand is already set then there is nothing to do. The instruction
308
  // is already registered in the use-list of the value.
309
9.78M
  if (CurrentValue == Val) {
310
8.15k
    return;
311
8.15k
  }
312
313
  // Remove the current instruction from the old value that we are removing.
314
9.77M
  if (CurrentValue) {
315
3.97M
    CurrentValue->removeUse(Operands[Index]);
316
3.97M
  }
317
318
  // Register this instruction as a user of the new value and set the operand.
319
9.77M
  if (Val) {
320
9.32M
    Operands[Index] = Val->addUser(this);
321
9.32M
  } else {
322
442k
    Operands[Index] = {nullptr, 0};
323
442k
  }
324
9.77M
}
325
326
27.5M
Value *Instruction::getOperand(unsigned Index) const {
327
27.5M
  return Operands[Index].first;
328
27.5M
}
329
330
16.8M
unsigned Instruction::getNumOperands() const {
331
16.8M
  return Operands.size();
332
16.8M
}
333
334
0
void Instruction::removeOperand(unsigned index) {
335
  // We call to setOperand before deleting the operand because setOperand
336
  // un-registers the user from the user list.
337
0
  setOperand(nullptr, index);
338
0
  Operands.erase(Operands.begin() + index);
339
0
}
340
341
1.27M
void Instruction::replaceFirstOperandWith(Value *OldValue, Value *NewValue) {
342
1.37M
  for (int i = 0, e = getNumOperands(); i < e; i++) {
343
1.37M
    if (OldValue == getOperand(i)) {
344
1.27M
      setOperand(NewValue, i);
345
1.27M
      return;
346
1.27M
    }
347
1.37M
  }
348
1.27M
  llvm_unreachable("Can't find operand. Invalid use-def chain.");
349
1.27M
}
350
351
0
void Instruction::eraseOperand(Value *Value) {
352
  // Overwrite all of the operands that we are removing with null. This will
353
  // unregister them from the use list.
354
0
  for (int i = 0, e = getNumOperands(); i < e; ++i) {
355
0
    if (getOperand(i) == Value)
356
0
      setOperand(nullptr, i);
357
0
  }
358
359
  // Now remove all null operands from the list.
360
0
  auto new_end = std::remove_if(
361
0
      Operands.begin(), Operands.end(), [](Use U) { return !U.first; });
362
0
  Operands.erase(new_end, Operands.end());
363
364
0
  assert(!Value->hasUser(this) && "corrupt uselist");
365
0
}
366
367
0
void Instruction::insertBefore(Instruction *InsertPos) {
368
0
  InsertPos->getParent()->getInstList().insert(InsertPos->getIterator(), this);
369
0
}
370
371
0
void Instruction::insertAfter(Instruction *InsertPos) {
372
0
  InsertPos->getParent()->getInstList().insertAfter(
373
0
      InsertPos->getIterator(), this);
374
0
}
375
376
0
void Instruction::moveBefore(Instruction *Later) {
377
0
  if (this == Later)
378
0
    return;
379
380
0
  getParent()->getInstList().remove(this);
381
0
  Later->getParent()->getInstList().insert(Later->getIterator(), this);
382
0
  setParent(Later->getParent());
383
0
}
384
385
0
void BasicBlock::remove(Instruction *I) {
386
0
  InstList.remove(I);
387
0
}
388
223k
void BasicBlock::erase(Instruction *I) {
389
223k
  InstList.erase(I);
390
223k
}
391
392
0
void Instruction::removeFromParent() {
393
0
  getParent()->remove(this);
394
0
}
395
223k
void Instruction::eraseFromParent() {
396
  // Release this instruction from the use-list of other instructions.
397
665k
  for (unsigned i = 0; i < getNumOperands(); i++)
398
442k
    setOperand(nullptr, i);
399
400
223k
  getParent()->erase(this);
401
223k
}
402
403
0
void Function::eraseFromParentNoDestroy() {
404
  // Erase all of the basic blocks before deleting the function.
405
0
  while (begin() != end()) {
406
0
    begin()->replaceAllUsesWith(nullptr);
407
0
    begin()->eraseFromParent();
408
0
  }
409
0
  assert(!hasUsers() && "Use list is not empty");
410
0
  getParent()->getFunctionList().remove(getIterator());
411
0
}
412
413
0
llvh::StringRef Instruction::getName() {
414
0
  switch (getKind()) {
415
0
    default:
416
0
      llvm_unreachable("Invalid kind");
417
0
#define DEF_VALUE(XX, PARENT) \
418
0
  case ValueKind::XX##Kind:   \
419
0
    return #XX;
420
0
#include "hermes/IR/Instrs.def"
421
0
  }
422
0
}
423
424
0
SideEffectKind Instruction::getDerivedSideEffect() {
425
0
  switch (getKind()) {
426
0
    default:
427
0
      llvm_unreachable("Invalid kind");
428
0
#define DEF_VALUE(XX, PARENT) \
429
0
  case ValueKind::XX##Kind:   \
430
0
    return cast<XX>(this)->getSideEffect();
431
0
#include "hermes/IR/Instrs.def"
432
0
  }
433
0
}
434
435
296k
WordBitSet<> Instruction::getChangedOperands() {
436
296k
  switch (getKind()) {
437
0
    default:
438
0
      llvm_unreachable("Invalid kind");
439
440
0
#define DEF_VALUE(XX, PARENT)                        \
441
296k
  case ValueKind::XX##Kind:                          \
442
296k
    return cast<XX>(this)->getChangedOperandsImpl(); \
443
0
    break;
444
296k
#include "hermes/IR/Instrs.def"
445
296k
  }
446
296k
}
447
448
Parameter::Parameter(Function *parent, Identifier name, bool isThisParameter)
449
3.69k
    : Value(ValueKind::ParameterKind), Parent(parent), Name(name) {
450
3.69k
  assert(Parent && "Invalid parent");
451
3.69k
  if (isThisParameter) {
452
1.91k
    Parent->setThisParameter(this);
453
1.91k
  } else {
454
1.78k
    Parent->addParameter(this);
455
1.78k
  }
456
3.69k
}
457
458
Variable::Variable(
459
    ValueKind k,
460
    ScopeDesc *scope,
461
    DeclKind declKind,
462
    Identifier txt)
463
1.80k
    : Value(k),
464
1.80k
      declKind(declKind),
465
1.80k
      text(txt),
466
1.80k
      parent(scope),
467
1.80k
      strictImmutableBinding_(declKind == DeclKind::Const) {
468
1.80k
  scope->addVariable(this);
469
1.80k
}
470
471
1.80k
Variable::~Variable() {}
472
473
7.66k
int Variable::getIndexInVariableList() const {
474
7.66k
  int index = 0;
475
18.9k
  for (auto V : parent->getVariables()) {
476
18.9k
    if (V == this)
477
7.66k
      return index;
478
11.2k
    index++;
479
11.2k
  }
480
7.66k
  llvm_unreachable("Cannot find variable in the variable list");
481
7.66k
}
482
483
0
Variable *Variable::cloneIntoNewScope(ScopeDesc *newScope) {
484
0
  Variable *clone = new Variable(parent, declKind, text);
485
0
  clone->strictImmutableBinding_ = strictImmutableBinding_;
486
0
  newScope->addVariable(clone);
487
0
  return clone;
488
0
}
489
490
0
Identifier Parameter::getName() const {
491
0
  return Name;
492
0
}
493
494
0
void BasicBlock::push_back(Instruction *I) {
495
0
  InstList.push_back(I);
496
0
}
497
498
621k
TerminatorInst *BasicBlock::getTerminator() {
499
621k
  if (InstList.empty())
500
0
    return nullptr;
501
621k
  return llvh::dyn_cast<TerminatorInst>(&InstList.back());
502
621k
}
503
504
121k
const TerminatorInst *BasicBlock::getTerminator() const {
505
121k
  if (InstList.empty())
506
0
    return nullptr;
507
121k
  return llvh::dyn_cast<TerminatorInst>(&InstList.back());
508
121k
}
509
510
0
void BasicBlock::removeFromParent() {
511
0
  getParent()->getBasicBlockList().remove(getIterator());
512
0
}
513
514
48
void BasicBlock::eraseFromParent() {
515
  // Erase all of the instructions in the block before deleting the block.
516
  // We are starting to delete from the start of the block. Naturally we will
517
  // have forward dependencies between instructions. To allow safe deletion
518
  // we replace all uses with the invalid null value. setOperand knows how
519
  // to deal with null values.
520
48
  while (begin() != end()) {
521
0
    begin()->replaceAllUsesWith(nullptr);
522
0
    begin()->eraseFromParent();
523
0
  }
524
525
48
  assert(!hasUsers() && "Use list is not empty");
526
  // Erase the block itself:
527
48
  getParent()->getBasicBlockList().erase(getIterator());
528
48
}
529
530
6.83M
Context &Function::getContext() const {
531
6.83M
  return parent_->getContext();
532
6.83M
}
533
534
62.5k
void Function::addBlock(BasicBlock *BB) {
535
62.5k
  BasicBlockList.push_back(BB);
536
62.5k
}
537
1.78k
void Function::addParameter(Parameter *A) {
538
1.78k
  Parameters.push_back(A);
539
1.78k
}
540
541
137
Module::~Module() {
542
137
  FunctionList.clear();
543
544
  // Free global properties.
545
137
  globalPropertyMap_.clear();
546
6.83k
  for (auto *prop : globalPropertyList_) {
547
6.83k
    Value::destroy(prop);
548
6.83k
  }
549
550
137
  llvh::SmallVector<Literal *, 32> toDelete;
551
552
  // Collect all literals.
553
  // Note that we cannot delete while iterating due to the implementation
554
  // of FoldingSet.
555
425k
  for (auto &L : literalNumbers) {
556
425k
    toDelete.push_back(&L);
557
425k
  }
558
137
  for (auto &L : literalBigInts) {
559
30
    toDelete.push_back(&L);
560
30
  }
561
8.19k
  for (auto &L : literalStrings) {
562
8.19k
    toDelete.push_back(&L);
563
8.19k
  }
564
  // Free the literals.
565
433k
  for (auto *L : toDelete) {
566
433k
    Value::destroy(L);
567
433k
  }
568
137
}
569
570
1.99k
void Module::push_back(Function *F) {
571
1.99k
  FunctionList.push_back(F);
572
1.99k
}
573
574
0
void Module::insert(iterator position, Function *F) {
575
0
  FunctionList.insert(position, F);
576
0
}
577
578
0
GlobalObjectProperty *Module::findGlobalProperty(Identifier name) {
579
0
  auto it = globalPropertyMap_.find(name);
580
0
  return it != globalPropertyMap_.end() ? it->second : nullptr;
581
0
}
582
583
GlobalObjectProperty *Module::addGlobalProperty(
584
    Identifier name,
585
6.83k
    bool declared) {
586
6.83k
  auto &ref = globalPropertyMap_[name];
587
588
6.83k
  if (!ref) {
589
6.83k
    ref = new GlobalObjectProperty(this, getLiteralString(name), declared);
590
6.83k
    globalPropertyList_.push_back(ref);
591
6.83k
  } else {
592
0
    ref->orDeclared(declared);
593
0
  }
594
595
6.83k
  return ref;
596
6.83k
}
597
598
0
void Module::eraseGlobalProperty(GlobalObjectProperty *prop) {
599
0
  globalPropertyMap_.erase(prop->getName()->getValue());
600
0
  auto it =
601
0
      std::find(globalPropertyList_.begin(), globalPropertyList_.end(), prop);
602
0
  if (it != globalPropertyList_.end()) {
603
0
    Value::destroy(*it);
604
0
    globalPropertyList_.erase(it);
605
0
  }
606
0
}
607
608
0
void Module::populateCJSModuleUseGraph() {
609
0
  if (!cjsModuleUseGraph_.empty()) {
610
0
    return;
611
0
  }
612
613
0
  for (Function &f : *this) {
614
0
    for (Instruction *user : f.getUsers()) {
615
      // Add an edge to f, from the function which uses f.
616
0
      cjsModuleUseGraph_[user->getParent()->getParent()].insert(&f);
617
0
    }
618
0
  }
619
0
}
620
621
0
llvh::DenseSet<Function *> Module::getFunctionsInSegment(uint32_t segment) {
622
0
  populateCJSModuleUseGraph();
623
624
  // Final set of functions which must be output when generating this segment.
625
0
  llvh::DenseSet<Function *> result{};
626
627
  // Current set of functions which we haven't inspected (the frontier).
628
  // Use this to perform graph search and find all used functions.
629
0
  llvh::SetVector<Function *> worklist{};
630
631
  // Populate the worklist initially with the wrapper functions for each module
632
  // in the given segment.
633
0
  for (Function *fn : cjsModuleSegmentMap_[segment]) {
634
0
    worklist.insert(fn);
635
0
  }
636
637
0
  while (!worklist.empty()) {
638
0
    Function *cur = worklist.back();
639
0
    worklist.pop_back();
640
0
    if (result.count(cur)) {
641
      // We've already visited this function and added its children, so don't do
642
      // it again.
643
0
      continue;
644
0
    }
645
0
    result.insert(cur);
646
    // The functions that are used by the function cur.
647
0
    const auto targets = cjsModuleUseGraph_[cur];
648
0
    worklist.insert(targets.begin(), targets.end());
649
0
  }
650
651
0
  return result;
652
0
}
653
654
4.49k
uint32_t Module::getTemplateObjectID(RawStringList &&rawStrings) {
655
  // Try inserting into the map with a dummy value.
656
4.49k
  auto res = templateObjectIDMap_.emplace(std::move(rawStrings), 0);
657
4.49k
  if (res.second) {
658
    // Insertion succeeded. Overwrite the value with the correct id.
659
248
    res.first->second = templateObjectIDMap_.size() - 1;
660
248
  }
661
4.49k
  return res.first->second;
662
4.49k
}
663
664
1.51M
Context &Instruction::getContext() const {
665
1.51M
  return Parent->getContext();
666
1.51M
}
667
1.51M
Context &BasicBlock::getContext() const {
668
1.51M
  return Parent->getContext();
669
1.51M
}
670
0
Context &Parameter::getContext() const {
671
0
  return Parent->getContext();
672
0
}
673
674
/// \returns true if this parameter is a 'this' parameter.
675
0
bool Parameter::isThisParameter() const {
676
0
  return Parent->getThisParameter() == this;
677
0
}
678
679
0
int Parameter::getIndexInParamList() const {
680
0
  int index = 0;
681
0
  for (auto P : Parent->getParameters()) {
682
0
    if (P == this)
683
0
      return index;
684
0
    index++;
685
0
  }
686
0
  llvm_unreachable("Cannot find parameter in the function");
687
0
}
688
689
0
void Function::dump(llvh::raw_ostream &os) const {
690
0
  IRPrinter D(getParent()->getContext(), os);
691
0
  D.visit(*this);
692
0
}
693
694
0
void Function::viewGraph() {
695
0
  ::viewGraph(this);
696
0
}
697
698
/// Strip the " #number" suffice of a generated internal name, or a name that
699
/// just happens to be in that format.
700
static inline Identifier stripInternalNameSuffix(
701
    Context &context,
702
1.99k
    Identifier originalName) {
703
1.99k
  auto originalStr = originalName.str();
704
1.99k
  auto e = originalStr.end();
705
706
1.99k
  if (!(e - originalStr.begin() >= 3 && e[-1] == '#' && e[-2] >= '0' &&
707
1.99k
        e[-2] <= '9')) {
708
1.99k
    return originalName;
709
1.99k
  }
710
711
0
  e -= 2;
712
0
  while (e != originalStr.begin() && e[-1] >= '0' && e[-1] <= '9') {
713
0
    --e;
714
0
  }
715
716
0
  if (!(e != originalStr.begin() && e[-1] == ' '))
717
0
    return originalName;
718
719
0
  --e;
720
0
  return context.getIdentifier(originalStr.slice(0, e - originalStr.begin()));
721
0
}
722
723
1.99k
Identifier Module::deriveUniqueInternalName(Identifier originalName) {
724
1.99k
  assert(originalName.isValid() && "originalName must be valid");
725
726
  // Check whether the original name already is in the form "... number#" and
727
  // if so, strip the suffix.
728
1.99k
  originalName = stripInternalNameSuffix(getContext(), originalName);
729
730
1.99k
  auto insertResult = internalNamesMap_.try_emplace(originalName, 0);
731
732
  // If inserted for the first time, there is no need for a suffix.
733
1.99k
  if (insertResult.second)
734
242
    return originalName;
735
736
  // Construct a suffix using the number of internal names derived from this
737
  // identifier.
738
1.75k
  ++insertResult.first->second;
739
1.75k
  char itoaBuf[16];
740
1.75k
  snprintf(itoaBuf, sizeof(itoaBuf), "%u", insertResult.first->second);
741
742
1.75k
  llvh::SmallString<32> buf;
743
1.75k
  buf.append(originalName.str());
744
1.75k
  buf.append(" ");
745
1.75k
  buf.append(itoaBuf);
746
1.75k
  buf.append("#");
747
748
1.75k
  return getContext().getIdentifier(buf);
749
1.99k
}
750
751
0
void Module::viewGraph() {
752
0
  for (auto &F : *this) {
753
0
    ::viewGraph(&F);
754
0
  }
755
0
}
756
757
0
void Module::dump(llvh::raw_ostream &os) const {
758
0
  IRPrinter D(getContext(), os);
759
0
  D.visit(*this);
760
0
}
761
762
1.03M
LiteralNumber *Module::getLiteralNumber(double value) {
763
  // Check to see if we've already seen this tuple before.
764
1.03M
  llvh::FoldingSetNodeID ID;
765
766
1.03M
  LiteralNumber::Profile(ID, value);
767
768
  // If this is not the first time we see this tuple then return the old copy.
769
1.03M
  void *InsertPos = nullptr;
770
1.03M
  if (LiteralNumber *LN = literalNumbers.FindNodeOrInsertPos(ID, InsertPos))
771
614k
    return LN;
772
773
425k
  auto New = new LiteralNumber(value);
774
425k
  literalNumbers.InsertNode(New, InsertPos);
775
425k
  return New;
776
1.03M
}
777
778
76
LiteralBigInt *Module::getLiteralBigInt(UniqueString *value) {
779
  // Check to see if we've already seen this tuple before.
780
76
  llvh::FoldingSetNodeID ID;
781
782
76
  LiteralBigInt::Profile(ID, value);
783
784
  // If this is not the first time we see this tuple then return the old copy.
785
76
  void *InsertPos = nullptr;
786
76
  if (LiteralBigInt *LN = literalBigInts.FindNodeOrInsertPos(ID, InsertPos))
787
46
    return LN;
788
789
30
  auto New = new LiteralBigInt(value);
790
30
  literalBigInts.InsertNode(New, InsertPos);
791
30
  return New;
792
76
}
793
794
324k
LiteralString *Module::getLiteralString(Identifier value) {
795
  // Check to see if we've already seen this tuple before.
796
324k
  llvh::FoldingSetNodeID ID;
797
798
324k
  LiteralString::Profile(ID, value);
799
800
  // If this is not the first time we see this tuple then return the old copy.
801
324k
  void *InsertPos = nullptr;
802
324k
  if (LiteralString *LS = literalStrings.FindNodeOrInsertPos(ID, InsertPos))
803
316k
    return LS;
804
805
8.19k
  auto New = new LiteralString(value);
806
8.19k
  literalStrings.InsertNode(New, InsertPos);
807
8.19k
  return New;
808
324k
}
809
810
462k
LiteralBool *Module::getLiteralBool(bool value) {
811
462k
  if (value)
812
433k
    return &literalTrue;
813
29.1k
  return &literalFalse;
814
462k
}
815
816
0
void Type::print(llvh::raw_ostream &OS) const {
817
0
  bool first = true;
818
0
  for (unsigned i = 0; i < (unsigned)Type::TypeKind::LAST_TYPE; i++) {
819
    // Don't print the object type annotations if the type is closure or regex.
820
0
    if (i == (unsigned)Type::TypeKind::Object &&
821
0
        (isClosureType() || isRegExpType())) {
822
0
      continue;
823
0
    }
824
825
0
    if (bitmask_ & (1 << i)) {
826
0
      if (!first) {
827
0
        OS << "|";
828
0
      }
829
830
0
      OS << getKindStr((Type::TypeKind)i);
831
0
      first = false;
832
0
    }
833
0
  }
834
0
}
835
836
0
raw_ostream &llvh::operator<<(raw_ostream &OS, const hermes::Type &T) {
837
0
  T.print(OS);
838
0
  return OS;
839
0
}