Coverage Report

Created: 2023-02-22 06:51

/src/hermes/lib/IR/IR.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 "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
3.34M
void Value::destroy(Value *V) {
50
3.34M
  if (!V)
51
674
    return;
52
53
3.34M
  switch (V->Kind) {
54
0
    default:
55
0
      llvm_unreachable("Invalid kind");
56
0
#define DEF_VALUE(XX, PARENT) \
57
3.34M
  case ValueKind::XX##Kind:   \
58
3.34M
    delete cast<XX>(V);       \
59
3.34M
    break;
60
3.34M
#include "hermes/IR/ValueKinds.def"
61
3.34M
  }
62
3.34M
}
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
447k
const Value::UseListTy &Value::getUsers() const {
76
447k
  return Users;
77
447k
}
78
79
757k
unsigned Value::getNumUsers() const {
80
757k
  return Users.size();
81
757k
}
82
83
228k
bool Value::hasUsers() const {
84
228k
  return Users.size();
85
228k
}
86
87
0
bool Value::hasOneUser() const {
88
0
  return 1 == Users.size();
89
0
}
90
91
2.32M
void Value::removeUse(Use U) {
92
2.32M
  assert(Users.size() && "Removing a user from an empty list");
93
0
  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
0
  Users[U.second] = Users.back();
100
2.32M
  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
2.32M
  if (U.second != Users.size()) {
105
1.49M
    Use oldUse = {this, static_cast<unsigned>(Users.size())};
106
1.49M
    auto &operands = Users[U.second]->Operands;
107
657M
    for (int i = 0, e = operands.size(); i < e; i++) {
108
657M
      if (operands[i] == oldUse) {
109
1.49M
        operands[i] = {this, U.second};
110
1.49M
        return;
111
1.49M
      }
112
657M
    }
113
1.49M
    llvm_unreachable("Can't find user in operand list");
114
1.49M
  }
115
2.32M
}
116
117
5.82M
Value::Use Value::addUser(Instruction *Inst) {
118
5.82M
  Users.push_back(Inst);
119
5.82M
  return {this, static_cast<unsigned>(Users.size() - 1)};
120
5.82M
}
121
122
490k
void Value::replaceAllUsesWith(Value *Other) {
123
490k
  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
1.05M
  while (Users.size()) {
130
560k
    Users[Users.size() - 1]->replaceFirstOperandWith(this, Other);
131
560k
  }
132
490k
}
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
114k
ScopeDesc::~ScopeDesc() {
147
114k
  for (ScopeDesc *inner : innerScopes_) {
148
114k
    Value::destroy(inner);
149
114k
  }
150
151
  // Free all variables.
152
114k
  for (auto *v : variables_) {
153
114k
    Value::destroy(v);
154
114k
  }
155
114k
}
156
157
0
bool ScopeDesc::isGlobalScope() const {
158
0
  return function_->isGlobalScope() &&
159
0
      function_->getFunctionScopeDesc() == this;
160
0
}
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
    : Value(kind),
174
      parent_(parent),
175
      isGlobal_(isGlobal),
176
      scopeDesc_(scopeDesc),
177
      originalOrInferredName_(originalName),
178
      definitionKind_(definitionKind),
179
      strictMode_(strictMode),
180
      SourceRange(sourceRange),
181
      sourceVisibility_(sourceVisibility),
182
114k
      internalName_(parent->deriveUniqueInternalName(originalName)) {
183
114k
  scopeDesc_->setFunction(this);
184
114k
  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
114k
  } else {
191
114k
    parent->push_back(this);
192
114k
  }
193
194
  // Derive internalName from originalName.
195
0
  assert(originalName.isValid() && "Function originalName must be valid");
196
114k
}
197
198
114k
Function::~Function() {
199
  // Free all parameters.
200
114k
  for (auto *p : Parameters) {
201
114k
    Value::destroy(p);
202
114k
  }
203
114k
  Value::destroy(thisParameter);
204
114k
}
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
229k
llvh::Optional<llvh::StringRef> Function::getSourceRepresentationStr() const {
226
229k
  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
229k
    case SourceVisibility::Default:
251
229k
    default: {
252
      // No need of special source representation for these cases, their
253
      // 'toString' will return `{ [ bytecode ] }` as the default.
254
229k
      return llvh::None;
255
229k
    }
256
229k
  }
257
229k
}
258
259
BasicBlock::BasicBlock(Function *parent)
260
267k
    : Value(ValueKind::BasicBlockKind), Parent(parent) {
261
267k
  assert(Parent && "Invalid parent function");
262
0
  Parent->addBlock(this);
263
267k
}
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
4.50M
void Instruction::pushOperand(Value *Val) {
298
4.50M
  Operands.push_back({nullptr, 0});
299
4.50M
  setOperand(Val, getNumOperands() - 1);
300
4.50M
}
301
302
6.82M
void Instruction::setOperand(Value *Val, unsigned Index) {
303
6.82M
  assert(Index < Operands.size() && "Not all operands have been pushed!");
304
305
0
  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
6.82M
  if (CurrentValue == Val) {
310
68
    return;
311
68
  }
312
313
  // Remove the current instruction from the old value that we are removing.
314
6.82M
  if (CurrentValue) {
315
2.32M
    CurrentValue->removeUse(Operands[Index]);
316
2.32M
  }
317
318
  // Register this instruction as a user of the new value and set the operand.
319
6.82M
  if (Val) {
320
5.82M
    Operands[Index] = Val->addUser(this);
321
5.82M
  } else {
322
999k
    Operands[Index] = {nullptr, 0};
323
999k
  }
324
6.82M
}
325
326
18.9M
Value *Instruction::getOperand(unsigned Index) const {
327
18.9M
  return Operands[Index].first;
328
18.9M
}
329
330
11.0M
unsigned Instruction::getNumOperands() const {
331
11.0M
  return Operands.size();
332
11.0M
}
333
334
19.7k
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
19.7k
  setOperand(nullptr, index);
338
19.7k
  Operands.erase(Operands.begin() + index);
339
19.7k
}
340
341
560k
void Instruction::replaceFirstOperandWith(Value *OldValue, Value *NewValue) {
342
1.03M
  for (int i = 0, e = getNumOperands(); i < e; i++) {
343
1.03M
    if (OldValue == getOperand(i)) {
344
560k
      setOperand(NewValue, i);
345
560k
      return;
346
560k
    }
347
1.03M
  }
348
560k
  llvm_unreachable("Can't find operand. Invalid use-def chain.");
349
560k
}
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
602k
void BasicBlock::erase(Instruction *I) {
389
602k
  InstList.erase(I);
390
602k
}
391
392
0
void Instruction::removeFromParent() {
393
0
  getParent()->remove(this);
394
0
}
395
602k
void Instruction::eraseFromParent() {
396
  // Release this instruction from the use-list of other instructions.
397
1.58M
  for (unsigned i = 0; i < getNumOperands(); i++)
398
980k
    setOperand(nullptr, i);
399
400
602k
  getParent()->erase(this);
401
602k
}
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
28
WordBitSet<> Instruction::getChangedOperands() {
436
28
  switch (getKind()) {
437
0
    default:
438
0
      llvm_unreachable("Invalid kind");
439
440
0
#define DEF_VALUE(XX, PARENT)                        \
441
28
  case ValueKind::XX##Kind:                          \
442
28
    return cast<XX>(this)->getChangedOperandsImpl(); \
443
0
    break;
444
28
#include "hermes/IR/Instrs.def"
445
28
  }
446
28
}
447
448
Parameter::Parameter(Function *parent, Identifier name)
449
228k
    : Value(ValueKind::ParameterKind), Parent(parent), Name(name) {
450
228k
  assert(Parent && "Invalid parent");
451
228k
  if (name.str() == "this") {
452
114k
    Parent->setThisParameter(this);
453
114k
  } else {
454
114k
    Parent->addParameter(this);
455
114k
  }
456
228k
}
457
458
Variable::Variable(
459
    ValueKind k,
460
    ScopeDesc *scope,
461
    DeclKind declKind,
462
    Identifier txt)
463
114k
    : Value(k), declKind(declKind), text(txt), parent(scope) {
464
114k
  scope->addVariable(this);
465
114k
}
466
467
114k
Variable::~Variable() {}
468
469
125k
int Variable::getIndexInVariableList() const {
470
125k
  int index = 0;
471
125k
  for (auto V : parent->getVariables()) {
472
125k
    if (V == this)
473
125k
      return index;
474
12
    index++;
475
12
  }
476
125k
  llvm_unreachable("Cannot find variable in the variable list");
477
125k
}
478
479
0
Identifier Parameter::getName() const {
480
0
  return Name;
481
0
}
482
483
0
void BasicBlock::push_back(Instruction *I) {
484
0
  InstList.push_back(I);
485
0
}
486
487
1.30M
TerminatorInst *BasicBlock::getTerminator() {
488
1.30M
  if (InstList.empty())
489
0
    return nullptr;
490
1.30M
  return llvh::dyn_cast<TerminatorInst>(&InstList.back());
491
1.30M
}
492
493
307k
const TerminatorInst *BasicBlock::getTerminator() const {
494
307k
  if (InstList.empty())
495
0
    return nullptr;
496
307k
  return llvh::dyn_cast<TerminatorInst>(&InstList.back());
497
307k
}
498
499
0
void BasicBlock::removeFromParent() {
500
0
  getParent()->getBasicBlockList().remove(getIterator());
501
0
}
502
503
6
void BasicBlock::eraseFromParent() {
504
  // Erase all of the instructions in the block before deleting the block.
505
  // We are starting to delete from the start of the block. Naturally we will
506
  // have forward dependencies between instructions. To allow safe deletion
507
  // we replace all uses with the invalid null value. setOperand knows how
508
  // to deal with null values.
509
6
  while (begin() != end()) {
510
0
    begin()->replaceAllUsesWith(nullptr);
511
0
    begin()->eraseFromParent();
512
0
  }
513
514
6
  assert(!hasUsers() && "Use list is not empty");
515
  // Erase the block itself:
516
0
  getParent()->getBasicBlockList().erase(getIterator());
517
6
}
518
519
3.06M
Context &Function::getContext() const {
520
3.06M
  return parent_->getContext();
521
3.06M
}
522
523
267k
void Function::addBlock(BasicBlock *BB) {
524
267k
  BasicBlockList.push_back(BB);
525
267k
}
526
114k
void Function::addParameter(Parameter *A) {
527
114k
  Parameters.push_back(A);
528
114k
}
529
530
56
Module::~Module() {
531
56
  FunctionList.clear();
532
533
  // Free global properties.
534
56
  globalPropertyMap_.clear();
535
3.40k
  for (auto *prop : globalPropertyList_) {
536
3.40k
    Value::destroy(prop);
537
3.40k
  }
538
539
56
  llvh::SmallVector<Literal *, 32> toDelete;
540
541
  // Collect all literals.
542
  // Note that we cannot delete while iterating due to the implementation
543
  // of FoldingSet.
544
220k
  for (auto &L : literalNumbers) {
545
220k
    toDelete.push_back(&L);
546
220k
  }
547
56
  for (auto &L : literalBigInts) {
548
0
    toDelete.push_back(&L);
549
0
  }
550
4.10k
  for (auto &L : literalStrings) {
551
4.10k
    toDelete.push_back(&L);
552
4.10k
  }
553
  // Free the literals.
554
224k
  for (auto *L : toDelete) {
555
224k
    Value::destroy(L);
556
224k
  }
557
56
}
558
559
114k
void Module::push_back(Function *F) {
560
114k
  FunctionList.push_back(F);
561
114k
}
562
563
0
void Module::insert(iterator position, Function *F) {
564
0
  FunctionList.insert(position, F);
565
0
}
566
567
0
GlobalObjectProperty *Module::findGlobalProperty(Identifier name) {
568
0
  auto it = globalPropertyMap_.find(name);
569
0
  return it != globalPropertyMap_.end() ? it->second : nullptr;
570
0
}
571
572
GlobalObjectProperty *Module::addGlobalProperty(
573
    Identifier name,
574
3.40k
    bool declared) {
575
3.40k
  auto &ref = globalPropertyMap_[name];
576
577
3.40k
  if (!ref) {
578
3.40k
    ref = new GlobalObjectProperty(this, getLiteralString(name), declared);
579
3.40k
    globalPropertyList_.push_back(ref);
580
3.40k
  } else {
581
0
    ref->orDeclared(declared);
582
0
  }
583
584
3.40k
  return ref;
585
3.40k
}
586
587
0
void Module::eraseGlobalProperty(GlobalObjectProperty *prop) {
588
0
  globalPropertyMap_.erase(prop->getName()->getValue());
589
0
  auto it =
590
0
      std::find(globalPropertyList_.begin(), globalPropertyList_.end(), prop);
591
0
  if (it != globalPropertyList_.end()) {
592
0
    Value::destroy(*it);
593
0
    globalPropertyList_.erase(it);
594
0
  }
595
0
}
596
597
0
void Module::populateCJSModuleUseGraph() {
598
0
  if (!cjsModuleUseGraph_.empty()) {
599
0
    return;
600
0
  }
601
602
0
  for (Function &f : *this) {
603
0
    for (Instruction *user : f.getUsers()) {
604
      // Add an edge to f, from the function which uses f.
605
0
      cjsModuleUseGraph_[user->getParent()->getParent()].insert(&f);
606
0
    }
607
0
  }
608
0
}
609
610
0
llvh::DenseSet<Function *> Module::getFunctionsInSegment(uint32_t segment) {
611
0
  populateCJSModuleUseGraph();
612
613
  // Final set of functions which must be output when generating this segment.
614
0
  llvh::DenseSet<Function *> result{};
615
616
  // Current set of functions which we haven't inspected (the frontier).
617
  // Use this to perform graph search and find all used functions.
618
0
  llvh::SetVector<Function *> worklist{};
619
620
  // Populate the worklist initially with the wrapper functions for each module
621
  // in the given segment.
622
0
  for (Function *fn : cjsModuleSegmentMap_[segment]) {
623
0
    worklist.insert(fn);
624
0
  }
625
626
0
  while (!worklist.empty()) {
627
0
    Function *cur = worklist.back();
628
0
    worklist.pop_back();
629
0
    if (result.count(cur)) {
630
      // We've already visited this function and added its children, so don't do
631
      // it again.
632
0
      continue;
633
0
    }
634
0
    result.insert(cur);
635
    // The functions that are used by the function cur.
636
0
    const auto targets = cjsModuleUseGraph_[cur];
637
0
    worklist.insert(targets.begin(), targets.end());
638
0
  }
639
640
0
  return result;
641
0
}
642
643
283
uint32_t Module::getTemplateObjectID(RawStringList &&rawStrings) {
644
  // Try inserting into the map with a dummy value.
645
283
  auto res = templateObjectIDMap_.emplace(std::move(rawStrings), 0);
646
283
  if (res.second) {
647
    // Insertion succeeded. Overwrite the value with the correct id.
648
69
    res.first->second = templateObjectIDMap_.size() - 1;
649
69
  }
650
283
  return res.first->second;
651
283
}
652
653
0
Context &Instruction::getContext() const {
654
0
  return Parent->getContext();
655
0
}
656
0
Context &BasicBlock::getContext() const {
657
0
  return Parent->getContext();
658
0
}
659
0
Context &Parameter::getContext() const {
660
0
  return Parent->getContext();
661
0
}
662
663
/// \returns true if this parameter is a 'this' parameter.
664
0
bool Parameter::isThisParameter() const {
665
0
  return Parent->getThisParameter() == this;
666
0
}
667
668
0
int Parameter::getIndexInParamList() const {
669
0
  int index = 0;
670
0
  for (auto P : Parent->getParameters()) {
671
0
    if (P == this)
672
0
      return index;
673
0
    index++;
674
0
  }
675
0
  llvm_unreachable("Cannot find parameter in the function");
676
0
}
677
678
0
void Function::dump(llvh::raw_ostream &os) const {
679
0
  IRPrinter D(getParent()->getContext(), os);
680
0
  D.visit(*this);
681
0
}
682
683
0
void Function::viewGraph() {
684
0
  ::viewGraph(this);
685
0
}
686
687
/// Strip the " #number" suffice of a generated internal name, or a name that
688
/// just happens to be in that format.
689
static inline Identifier stripInternalNameSuffix(
690
    Context &context,
691
114k
    Identifier originalName) {
692
114k
  auto originalStr = originalName.str();
693
114k
  auto e = originalStr.end();
694
695
114k
  if (!(e - originalStr.begin() >= 3 && e[-1] == '#' && e[-2] >= '0' &&
696
114k
        e[-2] <= '9')) {
697
114k
    return originalName;
698
114k
  }
699
700
0
  e -= 2;
701
0
  while (e != originalStr.begin() && e[-1] >= '0' && e[-1] <= '9') {
702
0
    --e;
703
0
  }
704
705
0
  if (!(e != originalStr.begin() && e[-1] == ' '))
706
0
    return originalName;
707
708
0
  --e;
709
0
  return context.getIdentifier(originalStr.slice(0, e - originalStr.begin()));
710
0
}
711
712
114k
Identifier Module::deriveUniqueInternalName(Identifier originalName) {
713
114k
  assert(originalName.isValid() && "originalName must be valid");
714
715
  // Check whether the original name already is in the form "... number#" and
716
  // if so, strip the suffix.
717
0
  originalName = stripInternalNameSuffix(getContext(), originalName);
718
719
114k
  auto insertResult = internalNamesMap_.try_emplace(originalName, 0);
720
721
  // If inserted for the first time, there is no need for a suffix.
722
114k
  if (insertResult.second)
723
66
    return originalName;
724
725
  // Construct a suffix using the number of internal names derived from this
726
  // identifier.
727
114k
  ++insertResult.first->second;
728
114k
  char itoaBuf[16];
729
114k
  snprintf(itoaBuf, sizeof(itoaBuf), "%u", insertResult.first->second);
730
731
114k
  llvh::SmallString<32> buf;
732
114k
  buf.append(originalName.str());
733
114k
  buf.append(" ");
734
114k
  buf.append(itoaBuf);
735
114k
  buf.append("#");
736
737
114k
  return getContext().getIdentifier(buf);
738
114k
}
739
740
0
void Module::viewGraph() {
741
0
  for (auto &F : *this) {
742
0
    ::viewGraph(&F);
743
0
  }
744
0
}
745
746
0
void Module::dump(llvh::raw_ostream &os) const {
747
0
  IRPrinter D(getContext(), os);
748
0
  D.visit(*this);
749
0
}
750
751
1.12M
LiteralNumber *Module::getLiteralNumber(double value) {
752
  // Check to see if we've already seen this tuple before.
753
1.12M
  llvh::FoldingSetNodeID ID;
754
755
1.12M
  LiteralNumber::Profile(ID, value);
756
757
  // If this is not the first time we see this tuple then return the old copy.
758
1.12M
  void *InsertPos = nullptr;
759
1.12M
  if (LiteralNumber *LN = literalNumbers.FindNodeOrInsertPos(ID, InsertPos))
760
901k
    return LN;
761
762
220k
  auto New = new LiteralNumber(value);
763
220k
  literalNumbers.InsertNode(New, InsertPos);
764
220k
  return New;
765
1.12M
}
766
767
0
LiteralBigInt *Module::getLiteralBigInt(UniqueString *value) {
768
  // Check to see if we've already seen this tuple before.
769
0
  llvh::FoldingSetNodeID ID;
770
771
0
  LiteralBigInt::Profile(ID, value);
772
773
  // If this is not the first time we see this tuple then return the old copy.
774
0
  void *InsertPos = nullptr;
775
0
  if (LiteralBigInt *LN = literalBigInts.FindNodeOrInsertPos(ID, InsertPos))
776
0
    return LN;
777
778
0
  auto New = new LiteralBigInt(value);
779
0
  literalBigInts.InsertNode(New, InsertPos);
780
0
  return New;
781
0
}
782
783
322k
LiteralString *Module::getLiteralString(Identifier value) {
784
  // Check to see if we've already seen this tuple before.
785
322k
  llvh::FoldingSetNodeID ID;
786
787
322k
  LiteralString::Profile(ID, value);
788
789
  // If this is not the first time we see this tuple then return the old copy.
790
322k
  void *InsertPos = nullptr;
791
322k
  if (LiteralString *LS = literalStrings.FindNodeOrInsertPos(ID, InsertPos))
792
318k
    return LS;
793
794
4.10k
  auto New = new LiteralString(value);
795
4.10k
  literalStrings.InsertNode(New, InsertPos);
796
4.10k
  return New;
797
322k
}
798
799
237k
LiteralBool *Module::getLiteralBool(bool value) {
800
237k
  if (value)
801
235k
    return &literalTrue;
802
2.03k
  return &literalFalse;
803
237k
}
804
805
0
void Type::print(llvh::raw_ostream &OS) const {
806
0
  bool first = true;
807
0
  for (unsigned i = 0; i < (unsigned)Type::TypeKind::LAST_TYPE; i++) {
808
    // Don't print the object type annotations if the type is closure or regex.
809
0
    if (i == (unsigned)Type::TypeKind::Object &&
810
0
        (isClosureType() || isRegExpType())) {
811
0
      continue;
812
0
    }
813
814
0
    if (bitmask_ & (1 << i)) {
815
0
      if (!first) {
816
0
        OS << "|";
817
0
      }
818
819
0
      OS << getKindStr((Type::TypeKind)i);
820
0
      first = false;
821
0
    }
822
0
  }
823
0
}
824
825
0
raw_ostream &llvh::operator<<(raw_ostream &OS, const hermes::Type &T) {
826
0
  T.print(OS);
827
0
  return OS;
828
0
}