Coverage Report

Created: 2025-12-11 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hermes/lib/VM/Interpreter.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
#define DEBUG_TYPE "vm"
9
#include "hermes/VM/Interpreter.h"
10
#include "hermes/VM/Runtime.h"
11
12
#include "hermes/Inst/InstDecode.h"
13
#include "hermes/Support/Conversions.h"
14
#include "hermes/Support/SlowAssert.h"
15
#include "hermes/Support/Statistic.h"
16
#include "hermes/VM/BigIntPrimitive.h"
17
#include "hermes/VM/Callable.h"
18
#include "hermes/VM/CodeBlock.h"
19
#include "hermes/VM/HandleRootOwner-inline.h"
20
#include "hermes/VM/JSArray.h"
21
#include "hermes/VM/JSError.h"
22
#include "hermes/VM/JSGenerator.h"
23
#include "hermes/VM/JSProxy.h"
24
#include "hermes/VM/JSRegExp.h"
25
#include "hermes/VM/JSTypedArray.h"
26
#include "hermes/VM/Operations.h"
27
#include "hermes/VM/Profiler.h"
28
#include "hermes/VM/Profiler/CodeCoverageProfiler.h"
29
#include "hermes/VM/PropertyAccessor.h"
30
#include "hermes/VM/RuntimeModule-inline.h"
31
#include "hermes/VM/StackFrame-inline.h"
32
#include "hermes/VM/StringPrimitive.h"
33
#include "hermes/VM/StringView.h"
34
#include "hermes/VM/WeakRoot-inline.h"
35
36
#include "llvh/Support/Debug.h"
37
#include "llvh/Support/Format.h"
38
#include "llvh/Support/raw_ostream.h"
39
40
#include "Interpreter-internal.h"
41
42
#pragma GCC diagnostic push
43
44
#ifdef HERMES_COMPILER_SUPPORTS_WSHORTEN_64_TO_32
45
#pragma GCC diagnostic ignored "-Wshorten-64-to-32"
46
#endif
47
using llvh::dbgs;
48
using namespace hermes::inst;
49
50
HERMES_SLOW_STATISTIC(
51
    NumGetById,
52
    "NumGetById: Number of property 'read by id' accesses");
53
HERMES_SLOW_STATISTIC(
54
    NumGetByIdCacheHits,
55
    "NumGetByIdCacheHits: Number of property 'read by id' cache hits");
56
HERMES_SLOW_STATISTIC(
57
    NumGetByIdProtoHits,
58
    "NumGetByIdProtoHits: Number of property 'read by id' cache hits for the prototype");
59
HERMES_SLOW_STATISTIC(
60
    NumGetByIdCacheEvicts,
61
    "NumGetByIdCacheEvicts: Number of property 'read by id' cache evictions");
62
HERMES_SLOW_STATISTIC(
63
    NumGetByIdFastPaths,
64
    "NumGetByIdFastPaths: Number of property 'read by id' fast paths");
65
HERMES_SLOW_STATISTIC(
66
    NumGetByIdAccessor,
67
    "NumGetByIdAccessor: Number of property 'read by id' accessors");
68
HERMES_SLOW_STATISTIC(
69
    NumGetByIdProto,
70
    "NumGetByIdProto: Number of property 'read by id' in the prototype chain");
71
HERMES_SLOW_STATISTIC(
72
    NumGetByIdNotFound,
73
    "NumGetByIdNotFound: Number of property 'read by id' not found");
74
HERMES_SLOW_STATISTIC(
75
    NumGetByIdTransient,
76
    "NumGetByIdTransient: Number of property 'read by id' of non-objects");
77
HERMES_SLOW_STATISTIC(
78
    NumGetByIdDict,
79
    "NumGetByIdDict: Number of property 'read by id' of dictionaries");
80
HERMES_SLOW_STATISTIC(
81
    NumGetByIdSlow,
82
    "NumGetByIdSlow: Number of property 'read by id' slow path");
83
84
HERMES_SLOW_STATISTIC(
85
    NumPutById,
86
    "NumPutById: Number of property 'write by id' accesses");
87
HERMES_SLOW_STATISTIC(
88
    NumPutByIdCacheHits,
89
    "NumPutByIdCacheHits: Number of property 'write by id' cache hits");
90
HERMES_SLOW_STATISTIC(
91
    NumPutByIdCacheEvicts,
92
    "NumPutByIdCacheEvicts: Number of property 'write by id' cache evictions");
93
HERMES_SLOW_STATISTIC(
94
    NumPutByIdFastPaths,
95
    "NumPutByIdFastPaths: Number of property 'write by id' fast paths");
96
HERMES_SLOW_STATISTIC(
97
    NumPutByIdTransient,
98
    "NumPutByIdTransient: Number of property 'write by id' to non-objects");
99
100
HERMES_SLOW_STATISTIC(
101
    NumNativeFunctionCalls,
102
    "NumNativeFunctionCalls: Number of native function calls");
103
HERMES_SLOW_STATISTIC(
104
    NumBoundFunctionCalls,
105
    "NumBoundCalls: Number of bound function calls");
106
107
// Ensure that instructions declared as having matching layouts actually do.
108
#include "InstLayout.inc"
109
110
namespace hermes {
111
namespace vm {
112
113
/// Initialize the state of some internal variables based on the current
114
/// code block.
115
#define INIT_STATE_FOR_CODEBLOCK(codeBlock)                      \
116
3.05k
  do {                                                           \
117
3.05k
    strictMode = (codeBlock)->isStrictMode();                    \
118
3.05k
    defaultPropOpFlags = DEFAULT_PROP_OP_FLAGS(strictMode);      \
119
3.05k
    if (EnableCrashTrace) {                                      \
120
0
      auto *bc = (codeBlock)->getRuntimeModule()->getBytecode(); \
121
0
      bytecodeFileStart = bc->getRawBuffer().data();             \
122
0
      auto hash = bc->getSourceHash();                           \
123
0
      runtime.crashTrace_.recordModule(                          \
124
0
          bc->getSegmentID(),                                    \
125
0
          (codeBlock)->getRuntimeModule()->getSourceURL(),       \
126
0
          llvh::StringRef((const char *)&hash, sizeof(hash)));   \
127
0
    }                                                            \
128
3.05k
  } while (0)
129
130
CallResult<PseudoHandle<JSGenerator>> Interpreter::createGenerator_RJS(
131
    Runtime &runtime,
132
    RuntimeModule *runtimeModule,
133
    unsigned funcIndex,
134
    Handle<Environment> envHandle,
135
0
    NativeArgs args) {
136
0
  auto gifRes = GeneratorInnerFunction::create(
137
0
      runtime,
138
0
      runtimeModule->getDomain(runtime),
139
0
      Handle<JSObject>::vmcast(&runtime.functionPrototype),
140
0
      envHandle,
141
0
      runtimeModule->getCodeBlockMayAllocate(funcIndex),
142
0
      args);
143
0
  if (LLVM_UNLIKELY(gifRes == ExecutionStatus::EXCEPTION)) {
144
0
    return ExecutionStatus::EXCEPTION;
145
0
  }
146
147
0
  auto generatorFunction = runtime.makeHandle(
148
0
      vmcast<JSGeneratorFunction>(
149
0
          runtime.getCurrentFrame().getCalleeClosureUnsafe()));
150
151
0
  auto prototypeProp = JSObject::getNamed_RJS(
152
0
      generatorFunction,
153
0
      runtime,
154
0
      Predefined::getSymbolID(Predefined::prototype));
155
0
  if (LLVM_UNLIKELY(prototypeProp == ExecutionStatus::EXCEPTION)) {
156
0
    return ExecutionStatus::EXCEPTION;
157
0
  }
158
0
  Handle<JSObject> prototype = vmisa<JSObject>(prototypeProp->get())
159
0
      ? runtime.makeHandle<JSObject>(prototypeProp->get())
160
0
      : Handle<JSObject>::vmcast(&runtime.generatorPrototype);
161
162
0
  return JSGenerator::create(runtime, *gifRes, prototype);
163
0
}
164
165
CallResult<Handle<Arguments>> Interpreter::reifyArgumentsSlowPath(
166
    Runtime &runtime,
167
    Handle<Callable> curFunction,
168
0
    bool strictMode) {
169
0
  auto frame = runtime.getCurrentFrame();
170
0
  uint32_t argCount = frame.getArgCount();
171
  // Define each JavaScript argument.
172
0
  auto argRes = Arguments::create(runtime, argCount, curFunction, strictMode);
173
0
  if (LLVM_UNLIKELY(argRes == ExecutionStatus::EXCEPTION)) {
174
0
    return ExecutionStatus::EXCEPTION;
175
0
  }
176
0
  Handle<Arguments> args = *argRes;
177
178
0
  for (uint32_t argIndex = 0; argIndex < argCount; ++argIndex) {
179
0
    SmallHermesValue shv =
180
0
        SmallHermesValue::encodeHermesValue(frame.getArgRef(argIndex), runtime);
181
0
    Arguments::unsafeSetExistingElementAt(*args, runtime, argIndex, shv);
182
0
  }
183
184
  // The returned value should already be set from the create call.
185
0
  return args;
186
0
}
187
188
CallResult<PseudoHandle<>> Interpreter::getArgumentsPropByValSlowPath_RJS(
189
    Runtime &runtime,
190
    PinnedHermesValue *lazyReg,
191
    PinnedHermesValue *valueReg,
192
    Handle<Callable> curFunction,
193
0
    bool strictMode) {
194
0
  auto frame = runtime.getCurrentFrame();
195
196
  // If the arguments object has already been created.
197
0
  if (!lazyReg->isUndefined()) {
198
    // The arguments object has been created, so this is a regular property
199
    // get.
200
0
    assert(lazyReg->isObject() && "arguments lazy register is not an object");
201
202
0
    return JSObject::getComputed_RJS(
203
0
        Handle<JSObject>::vmcast(lazyReg), runtime, Handle<>(valueReg));
204
0
  }
205
206
0
  if (!valueReg->isSymbol()) {
207
    // Attempt a fast path in the case that the key is not a symbol.
208
    // If it is a symbol, force reification for now.
209
    // Convert the value to a string.
210
0
    auto strRes = toString_RJS(runtime, Handle<>(valueReg));
211
0
    if (strRes == ExecutionStatus::EXCEPTION)
212
0
      return ExecutionStatus::EXCEPTION;
213
0
    auto strPrim = runtime.makeHandle(std::move(*strRes));
214
215
    // Check if the string is a valid argument index.
216
0
    if (auto index = toArrayIndex(runtime, strPrim)) {
217
0
      if (*index < frame.getArgCount()) {
218
0
        return createPseudoHandle(frame.getArgRef(*index));
219
0
      }
220
221
0
      auto objectPrototype = Handle<JSObject>::vmcast(&runtime.objectPrototype);
222
223
      // OK, they are requesting an index that either doesn't exist or is
224
      // somewhere up in the prototype chain. Since we want to avoid reifying,
225
      // check which it is:
226
0
      MutableHandle<JSObject> inObject{runtime};
227
0
      MutableHandle<SymbolID> inNameTmpStorage{runtime};
228
0
      ComputedPropertyDescriptor desc;
229
0
      JSObject::getComputedPrimitiveDescriptor(
230
0
          objectPrototype, runtime, strPrim, inObject, inNameTmpStorage, desc);
231
232
      // If we couldn't find the property, just return 'undefined'.
233
0
      if (!inObject)
234
0
        return createPseudoHandle(HermesValue::encodeUndefinedValue());
235
236
      // If the property isn't an accessor, we can just return it without
237
      // reifying.
238
0
      if (!desc.flags.accessor) {
239
0
        return JSObject::getComputedSlotValue(
240
0
            createPseudoHandle(inObject.get()),
241
0
            runtime,
242
0
            inNameTmpStorage,
243
0
            desc);
244
0
      }
245
0
    }
246
247
    // Are they requesting "arguments.length"?
248
0
    if (runtime.symbolEqualsToStringPrim(
249
0
            Predefined::getSymbolID(Predefined::length), *strPrim)) {
250
0
      return createPseudoHandle(
251
0
          HermesValue::encodeUntrustedNumberValue(frame.getArgCount()));
252
0
    }
253
0
  }
254
255
  // Looking for an accessor or a property that needs reification.
256
0
  auto argRes = reifyArgumentsSlowPath(runtime, curFunction, strictMode);
257
0
  if (argRes == ExecutionStatus::EXCEPTION) {
258
0
    return ExecutionStatus::EXCEPTION;
259
0
  }
260
261
  // Update the register with the reified value.
262
0
  *lazyReg = argRes->getHermesValue();
263
264
  // For simplicity, call ourselves again.
265
0
  return getArgumentsPropByValSlowPath_RJS(
266
0
      runtime, lazyReg, valueReg, curFunction, strictMode);
267
0
}
268
269
CallResult<PseudoHandle<>> Interpreter::handleCallSlowPath(
270
    Runtime &runtime,
271
657
    PinnedHermesValue *callTarget) {
272
657
  if (auto *native = dyn_vmcast<NativeFunction>(*callTarget)) {
273
656
    ++NumNativeFunctionCalls;
274
    // Call the native function directly
275
656
    return NativeFunction::_nativeCall(native, runtime);
276
656
  } else if (auto *bound = dyn_vmcast<BoundFunction>(*callTarget)) {
277
0
    ++NumBoundFunctionCalls;
278
    // Call the bound function.
279
0
    return BoundFunction::_boundCall(bound, runtime.getCurrentIP(), runtime);
280
1
  } else {
281
1
    return runtime.raiseTypeErrorForCallable(Handle<>(callTarget));
282
1
  }
283
657
}
284
285
inline PseudoHandle<> Interpreter::tryGetPrimitiveOwnPropertyById(
286
    Runtime &runtime,
287
    Handle<> base,
288
0
    SymbolID id) {
289
0
  if (base->isString() && id == Predefined::getSymbolID(Predefined::length)) {
290
0
    return createPseudoHandle(
291
0
        HermesValue::encodeUntrustedNumberValue(
292
0
            base->getString()->getStringLength()));
293
0
  }
294
0
  return createPseudoHandle(HermesValue::encodeEmptyValue());
295
0
}
296
297
CallResult<PseudoHandle<>> Interpreter::getByIdTransient_RJS(
298
    Runtime &runtime,
299
    Handle<> base,
300
0
    SymbolID id) {
301
  // This is similar to what ES5.1 8.7.1 special [[Get]] internal
302
  // method did, but that section doesn't exist in ES9 anymore.
303
  // Instead, the [[Get]] Receiver argument serves a similar purpose.
304
305
  // Fast path: try to get primitive own property directly first.
306
0
  PseudoHandle<> valOpt = tryGetPrimitiveOwnPropertyById(runtime, base, id);
307
0
  if (!valOpt->isEmpty()) {
308
0
    return valOpt;
309
0
  }
310
311
  // get the property descriptor from primitive prototype without
312
  // boxing with vm::toObject().  This is where any properties will
313
  // be.
314
0
  CallResult<Handle<JSObject>> primitivePrototypeResult =
315
0
      getPrimitivePrototype(runtime, base);
316
0
  if (primitivePrototypeResult == ExecutionStatus::EXCEPTION) {
317
    // If an exception is thrown, likely we are trying to read property on
318
    // undefined/null. Passing over the name of the property
319
    // so that we could emit more meaningful error messages.
320
0
    return amendPropAccessErrorMsgWithPropName(runtime, base, "read", id);
321
0
  }
322
323
0
  return JSObject::getNamedWithReceiver_RJS(
324
0
      *primitivePrototypeResult, runtime, id, base);
325
0
}
326
327
PseudoHandle<> Interpreter::getByValTransientFast(
328
    Runtime &runtime,
329
    Handle<> base,
330
0
    Handle<> nameHandle) {
331
0
  if (base->isString()) {
332
    // Handle most common fast path -- array index property for string
333
    // primitive.
334
    // Since primitive string cannot have index like property we can
335
    // skip ObjectFlags::fastIndexProperties checking and directly
336
    // checking index storage from StringPrimitive.
337
338
0
    OptValue<uint32_t> arrayIndex = toArrayIndexFastPath(*nameHandle);
339
    // Get character directly from primitive if arrayIndex is within range.
340
    // Otherwise we need to fall back to prototype lookup.
341
0
    if (arrayIndex &&
342
0
        arrayIndex.getValue() < base->getString()->getStringLength()) {
343
0
      return createPseudoHandle(
344
0
          runtime
345
0
              .getCharacterString(base->getString()->at(arrayIndex.getValue()))
346
0
              .getHermesValue());
347
0
    }
348
0
  }
349
0
  return createPseudoHandle(HermesValue::encodeEmptyValue());
350
0
}
351
352
CallResult<PseudoHandle<>> Interpreter::getByValTransient_RJS(
353
    Runtime &runtime,
354
    Handle<> base,
355
0
    Handle<> name) {
356
  // This is similar to what ES5.1 8.7.1 special [[Get]] internal
357
  // method did, but that section doesn't exist in ES9 anymore.
358
  // Instead, the [[Get]] Receiver argument serves a similar purpose.
359
360
  // Optimization: check fast path first.
361
0
  PseudoHandle<> fastRes = getByValTransientFast(runtime, base, name);
362
0
  if (!fastRes->isEmpty()) {
363
0
    return fastRes;
364
0
  }
365
366
0
  auto res = toObject(runtime, base);
367
0
  if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION))
368
0
    return ExecutionStatus::EXCEPTION;
369
370
0
  return JSObject::getComputedWithReceiver_RJS(
371
0
      runtime.makeHandle<JSObject>(res.getValue()), runtime, name, base);
372
0
}
373
374
static ExecutionStatus
375
0
transientObjectPutErrorMessage(Runtime &runtime, Handle<> base, SymbolID id) {
376
  // Emit an error message that looks like:
377
  // "Cannot create property '%{id}' on ${typeof base} '${String(base)}'".
378
0
  StringView propName = runtime.getIdentifierTable().getStringView(runtime, id);
379
0
  Handle<StringPrimitive> baseType =
380
0
      runtime.makeHandle(vmcast<StringPrimitive>(typeOf(runtime, base)));
381
0
  StringView baseTypeAsString =
382
0
      StringPrimitive::createStringView(runtime, baseType);
383
0
  MutableHandle<StringPrimitive> valueAsString{runtime};
384
0
  if (base->isSymbol()) {
385
    // Special workaround for Symbol which can't be stringified.
386
0
    auto str = symbolDescriptiveString(runtime, Handle<SymbolID>::vmcast(base));
387
0
    if (str != ExecutionStatus::EXCEPTION) {
388
0
      valueAsString = *str;
389
0
    } else {
390
0
      runtime.clearThrownValue();
391
0
      valueAsString = StringPrimitive::createNoThrow(
392
0
          runtime, "<<Exception occurred getting the value>>");
393
0
    }
394
0
  } else {
395
0
    auto str = toString_RJS(runtime, base);
396
0
    assert(
397
0
        str != ExecutionStatus::EXCEPTION &&
398
0
        "Primitives should be convertible to string without exceptions");
399
0
    valueAsString = std::move(*str);
400
0
  }
401
0
  StringView valueAsStringPrintable =
402
0
      StringPrimitive::createStringView(runtime, valueAsString);
403
404
0
  SmallU16String<32> tmp1;
405
0
  SmallU16String<32> tmp2;
406
0
  return runtime.raiseTypeError(
407
0
      TwineChar16("Cannot create property '") + propName + "' on " +
408
0
      baseTypeAsString.getUTF16Ref(tmp1) + " '" +
409
0
      valueAsStringPrintable.getUTF16Ref(tmp2) + "'");
410
0
}
411
412
ExecutionStatus Interpreter::putByIdTransient_RJS(
413
    Runtime &runtime,
414
    Handle<> base,
415
    SymbolID id,
416
    Handle<> value,
417
0
    bool strictMode) {
418
  // ES5.1 8.7.2 special [[Get]] internal method.
419
  // TODO: avoid boxing primitives unless we are calling an accessor.
420
421
  // 1. Let O be ToObject(base)
422
0
  auto res = toObject(runtime, base);
423
0
  if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
424
    // If an exception is thrown, likely we are trying to convert
425
    // undefined/null to an object. Passing over the name of the property
426
    // so that we could emit more meaningful error messages.
427
0
    return amendPropAccessErrorMsgWithPropName(runtime, base, "set", id);
428
0
  }
429
430
0
  auto O = runtime.makeHandle<JSObject>(res.getValue());
431
432
0
  NamedPropertyDescriptor desc;
433
0
  JSObject *propObj = JSObject::getNamedDescriptorUnsafe(O, runtime, id, desc);
434
435
  // Is this a missing property, or a data property defined in the prototype
436
  // chain? In both cases we would need to create an own property on the
437
  // transient object, which is prohibited.
438
0
  if (!propObj ||
439
0
      (propObj != O.get() &&
440
0
       (!desc.flags.accessor && !desc.flags.proxyObject))) {
441
0
    if (strictMode) {
442
0
      return transientObjectPutErrorMessage(runtime, base, id);
443
0
    }
444
0
    return ExecutionStatus::RETURNED;
445
0
  }
446
447
  // Modifying an own data property in a transient object is prohibited.
448
0
  if (!desc.flags.accessor && !desc.flags.proxyObject) {
449
0
    if (strictMode) {
450
0
      return runtime.raiseTypeError(
451
0
          "Cannot modify a property in a transient object");
452
0
    }
453
0
    return ExecutionStatus::RETURNED;
454
0
  }
455
456
0
  if (desc.flags.accessor) {
457
    // This is an accessor.
458
0
    auto *accessor = vmcast<PropertyAccessor>(
459
0
        JSObject::getNamedSlotValueUnsafe(propObj, runtime, desc)
460
0
            .getObject(runtime));
461
462
    // It needs to have a setter.
463
0
    if (!accessor->setter) {
464
0
      if (strictMode) {
465
0
        return runtime.raiseTypeError("Cannot modify a read-only accessor");
466
0
      }
467
0
      return ExecutionStatus::RETURNED;
468
0
    }
469
470
0
    CallResult<PseudoHandle<>> setRes =
471
0
        accessor->setter.getNonNull(runtime)->executeCall1(
472
0
            runtime.makeHandle(accessor->setter), runtime, base, *value);
473
0
    if (setRes == ExecutionStatus::EXCEPTION) {
474
0
      return ExecutionStatus::EXCEPTION;
475
0
    }
476
0
  } else {
477
0
    assert(desc.flags.proxyObject && "descriptor flags are impossible");
478
0
    CallResult<bool> setRes = JSProxy::setNamed(
479
0
        runtime.makeHandle(propObj), runtime, id, value, base);
480
0
    if (setRes == ExecutionStatus::EXCEPTION) {
481
0
      return ExecutionStatus::EXCEPTION;
482
0
    }
483
0
    if (!*setRes && strictMode) {
484
0
      return runtime.raiseTypeError("transient proxy set returned false");
485
0
    }
486
0
  }
487
0
  return ExecutionStatus::RETURNED;
488
0
}
489
490
ExecutionStatus Interpreter::putByValTransient_RJS(
491
    Runtime &runtime,
492
    Handle<> base,
493
    Handle<> name,
494
    Handle<> value,
495
0
    bool strictMode) {
496
0
  auto idRes = valueToSymbolID(runtime, name);
497
0
  if (idRes == ExecutionStatus::EXCEPTION)
498
0
    return ExecutionStatus::EXCEPTION;
499
500
0
  return putByIdTransient_RJS(runtime, base, **idRes, value, strictMode);
501
0
}
502
503
static Handle<HiddenClass> getHiddenClassForBuffer(
504
    Runtime &runtime,
505
    CodeBlock *curCodeBlock,
506
    unsigned numLiterals,
507
0
    unsigned keyBufferIndex) {
508
0
  RuntimeModule *runtimeModule = curCodeBlock->getRuntimeModule();
509
0
  if (auto clazzOpt = runtimeModule->findCachedLiteralHiddenClass(
510
0
          runtime, keyBufferIndex, numLiterals))
511
0
    return *clazzOpt;
512
513
0
  MutableHandle<> tmpHandleKey{runtime};
514
0
  MutableHandle<HiddenClass> clazz =
515
0
      runtime.makeMutableHandle(*runtime.getHiddenClassForPrototype(
516
0
          vmcast<JSObject>(runtime.objectPrototype),
517
0
          JSObject::numOverlapSlots<JSObject>()));
518
519
0
  GCScopeMarkerRAII marker{runtime};
520
0
  auto keyGen =
521
0
      curCodeBlock->getObjectBufferKeyIter(keyBufferIndex, numLiterals);
522
0
  while (keyGen.hasNext()) {
523
0
    auto key = keyGen.get(runtime);
524
0
    SymbolID sym = [&] {
525
0
      if (key.isSymbol())
526
0
        return ID(key.getSymbol().unsafeGetIndex());
527
528
0
      assert(key.isNumber() && "Key must be symbol or number");
529
0
      tmpHandleKey = key;
530
      // Note that since this handle has been created, the associated symbol
531
      // will be automatically kept alive until we flush the marker.
532
      // valueToSymbolID cannot fail because the key is known to be uint32.
533
0
      Handle<SymbolID> symHandle = *valueToSymbolID(runtime, tmpHandleKey);
534
0
      return *symHandle;
535
0
    }();
536
0
    auto addResult = HiddenClass::addProperty(
537
0
        clazz, runtime, sym, PropertyFlags::defaultNewNamedPropertyFlags());
538
0
    clazz = addResult->first;
539
0
    marker.flush();
540
0
  }
541
542
0
  if (LLVM_LIKELY(!clazz->isDictionary())) {
543
0
    assert(
544
0
        numLiterals == clazz->getNumProperties() &&
545
0
        "numLiterals should match hidden class property count.");
546
0
    assert(
547
0
        clazz->getNumProperties() < 256 &&
548
0
        "cached hidden class should have property count less than 256");
549
0
    runtimeModule->tryCacheLiteralHiddenClass(runtime, keyBufferIndex, *clazz);
550
0
  }
551
552
0
  return {clazz};
553
0
}
554
555
CallResult<PseudoHandle<>> Interpreter::createObjectFromBuffer(
556
    Runtime &runtime,
557
    CodeBlock *curCodeBlock,
558
    unsigned numLiterals,
559
    unsigned keyBufferIndex,
560
0
    unsigned valBufferIndex) {
561
  // Create a new object using the built-in constructor or cached hidden class.
562
  // Note that the built-in constructor is empty, so we don't actually need to
563
  // call it.
564
0
  auto clazz = getHiddenClassForBuffer(
565
0
      runtime, curCodeBlock, numLiterals, keyBufferIndex);
566
0
  auto obj = runtime.makeHandle(JSObject::create(runtime, clazz));
567
568
0
  auto valGen =
569
0
      curCodeBlock->getObjectBufferValueIter(valBufferIndex, numLiterals);
570
571
0
#ifndef NDEBUG
572
0
  auto keyGen =
573
0
      curCodeBlock->getObjectBufferKeyIter(keyBufferIndex, numLiterals);
574
0
#endif
575
576
0
  uint32_t propIndex = 0;
577
  // keyGen should always have the same amount of elements as valGen
578
0
  while (valGen.hasNext()) {
579
0
#ifndef NDEBUG
580
0
    {
581
0
      GCScopeMarkerRAII marker{runtime};
582
      // keyGen points to an element in the key buffer, which means it will
583
      // only ever generate a Number or a Symbol. This means it will never
584
      // allocate memory, and it is safe to not use a Handle.
585
0
      SymbolID stringIdResult{};
586
0
      auto key = keyGen.get(runtime);
587
0
      if (key.isSymbol()) {
588
0
        stringIdResult = ID(key.getSymbol().unsafeGetIndex());
589
0
      } else {
590
0
        auto keyHandle = runtime.makeHandle(
591
0
            HermesValue::encodeUntrustedNumberValue(key.getNumber()));
592
0
        auto idRes = valueToSymbolID(runtime, keyHandle);
593
0
        assert(
594
0
            idRes != ExecutionStatus::EXCEPTION &&
595
0
            "valueToIdentifier() failed for uint32_t value");
596
0
        stringIdResult = **idRes;
597
0
      }
598
0
      NamedPropertyDescriptor desc;
599
0
      auto pos = HiddenClass::findProperty(
600
0
          clazz,
601
0
          runtime,
602
0
          stringIdResult,
603
0
          PropertyFlags::defaultNewNamedPropertyFlags(),
604
0
          desc);
605
0
      assert(
606
0
          pos &&
607
0
          "Should find this property in cached hidden class property table.");
608
0
      assert(
609
0
          desc.slot == propIndex &&
610
0
          "propIndex should be the same as recorded in hidden class table.");
611
0
    }
612
0
#endif
613
    // Explicitly make sure valGen.get() is called before obj.get() so that
614
    // any allocation in valGen.get() won't invalidate the raw pointer
615
    // returned from obj.get().
616
0
    auto val = valGen.get(runtime);
617
0
    auto shv = SmallHermesValue::encodeHermesValue(val, runtime);
618
    // We made this object, it's not a Proxy.
619
0
    JSObject::setNamedSlotValueUnsafe(obj.get(), runtime, propIndex, shv);
620
0
    ++propIndex;
621
0
  }
622
623
0
  return createPseudoHandle(HermesValue::encodeObjectValue(*obj));
624
0
}
625
626
CallResult<PseudoHandle<>> Interpreter::createArrayFromBuffer(
627
    Runtime &runtime,
628
    CodeBlock *curCodeBlock,
629
    unsigned numElements,
630
    unsigned numLiterals,
631
6
    unsigned bufferIndex) {
632
  // Create a new array using the built-in constructor, and initialize
633
  // the elements from a literal array buffer.
634
6
  auto arrRes = JSArray::create(runtime, numElements, numElements);
635
6
  if (arrRes == ExecutionStatus::EXCEPTION) {
636
0
    return ExecutionStatus::EXCEPTION;
637
0
  }
638
  // Resize the array storage in advance.
639
6
  auto arr = *arrRes;
640
6
  JSArray::setStorageEndIndex(arr, runtime, numElements);
641
642
6
  auto iter = curCodeBlock->getArrayBufferIter(bufferIndex, numLiterals);
643
6
  JSArray::size_type i = 0;
644
50.3k
  while (iter.hasNext()) {
645
    // NOTE: we must get the value in a separate step to guarantee ordering.
646
50.3k
    const auto value =
647
50.3k
        SmallHermesValue::encodeHermesValue(iter.get(runtime), runtime);
648
50.3k
    JSArray::unsafeSetExistingElementAt(*arr, runtime, i++, value);
649
50.3k
  }
650
651
6
  return createPseudoHandle(HermesValue::encodeObjectValue(*arr));
652
6
}
653
654
#ifndef NDEBUG
655
656
0
llvh::raw_ostream &operator<<(llvh::raw_ostream &OS, DumpHermesValue dhv) {
657
0
  OS << dhv.hv;
658
  // If it is a string, dump the contents, truncated to 8 characters.
659
0
  if (dhv.hv.isString()) {
660
0
    SmallU16String<32> str;
661
0
    dhv.hv.getString()->appendUTF16String(str);
662
0
    UTF16Ref ref = str.arrayRef();
663
0
    if (str.size() <= 8) {
664
0
      OS << ":'" << ref << "'";
665
0
    } else {
666
0
      OS << ":'" << ref.slice(0, 8) << "'";
667
0
      OS << "...[" << str.size() << "]";
668
0
    }
669
0
  }
670
0
  return OS;
671
0
}
672
673
void dumpCallArguments(
674
    llvh::raw_ostream &OS,
675
    Runtime &runtime,
676
0
    StackFramePtr calleeFrame) {
677
0
  OS << "arguments:\n";
678
0
  OS << "  " << 0 << " " << DumpHermesValue(calleeFrame.getThisArgRef())
679
0
     << "\n";
680
0
  for (unsigned i = 0; i < calleeFrame.getArgCount(); ++i) {
681
0
    OS << "  " << (i + 1) << " " << DumpHermesValue(calleeFrame.getArgRef(i))
682
0
       << "\n";
683
0
  }
684
0
}
685
686
LLVM_ATTRIBUTE_UNUSED
687
static void printDebugInfo(
688
    CodeBlock *curCodeBlock,
689
    PinnedHermesValue *frameRegs,
690
8.25M
    const Inst *ip) {
691
  // Check if LLVm debugging is enabled for us.
692
8.25M
  bool debug = false;
693
8.25M
  SLOW_DEBUG(debug = true);
694
8.25M
  if (!debug)
695
8.25M
    return;
696
697
0
  DecodedInstruction decoded = decodeInstruction(ip);
698
699
0
  dbgs() << llvh::format_decimal((const uint8_t *)ip - curCodeBlock->begin(), 4)
700
0
         << " OpCode::" << getOpCodeString(decoded.meta.opCode);
701
702
0
  for (unsigned i = 0; i < decoded.meta.numOperands; ++i) {
703
0
    auto operandType = decoded.meta.operandType[i];
704
0
    auto value = decoded.operandValue[i];
705
706
0
    dbgs() << (i == 0 ? " " : ", ");
707
0
    dumpOperand(dbgs(), operandType, value);
708
709
0
    if (operandType == OperandType::Reg8 || operandType == OperandType::Reg32) {
710
      // Print the register value, if source.
711
0
      if (i != 0 || decoded.meta.numOperands == 1)
712
0
        dbgs() << "="
713
0
               << DumpHermesValue(REG(static_cast<uint32_t>(value.integer)));
714
0
    }
715
0
  }
716
717
0
  dbgs() << "\n";
718
0
}
719
720
#endif
721
722
/// \return the address of the next instruction after \p ip, which must be a
723
/// call-type instruction.
724
LLVM_ATTRIBUTE_ALWAYS_INLINE
725
1.41k
static inline const Inst *nextInstCall(const Inst *ip) {
726
1.41k
  HERMES_SLOW_ASSERT(isCallType(ip->opCode) && "ip is not of call type");
727
728
  // To avoid needing a large lookup table or switchcase, the following packs
729
  // information about the size of each call opcode into a uint32_t. Each call
730
  // type is represented with two bits, representing how much larger it is than
731
  // the smallest call instruction.
732
  // If we used 64 bits, we could fit the actual size of each call, without
733
  // needing the offset, and this may be necessary if new call instructions are
734
  // added in the future. For now however, due to limitations on loading large
735
  // immediates in ARM, it is significantly more efficient to use a uint32_t
736
  // than a uint64_t.
737
1.41k
  constexpr auto firstCall = std::min({
738
14.1k
#define DEFINE_RET_TARGET(name) static_cast<uint8_t>(OpCode::name),
739
1.41k
#include "hermes/BCGen/HBC/BytecodeList.def"
740
1.41k
  });
741
1.41k
  constexpr auto lastCall = std::max({
742
14.1k
#define DEFINE_RET_TARGET(name) static_cast<uint8_t>(OpCode::name),
743
1.41k
#include "hermes/BCGen/HBC/BytecodeList.def"
744
1.41k
  });
745
1.41k
  constexpr auto minSize = std::min({
746
14.1k
#define DEFINE_RET_TARGET(name) sizeof(inst::name##Inst),
747
1.41k
#include "hermes/BCGen/HBC/BytecodeList.def"
748
1.41k
  });
749
1.41k
  constexpr auto maxSize = std::max({
750
14.1k
#define DEFINE_RET_TARGET(name) sizeof(inst::name##Inst),
751
1.41k
#include "hermes/BCGen/HBC/BytecodeList.def"
752
1.41k
  });
753
754
1.41k
  constexpr uint32_t W = 2;
755
1.41k
  constexpr uint32_t mask = (1 << W) - 1;
756
757
1.41k
  static_assert(llvh::isUInt<W>(maxSize - minSize), "Size range too large.");
758
1.41k
  static_assert((lastCall - firstCall + 1) * W <= 32, "Too many call opcodes.");
759
760
1.41k
  constexpr uint32_t callSizes = 0
761
1.41k
#define DEFINE_RET_TARGET(name)             \
762
14.1k
  |                                         \
763
14.1k
      ((sizeof(inst::name##Inst) - minSize) \
764
14.1k
       << (((uint8_t)OpCode::name - firstCall) * W))
765
1.41k
#include "hermes/BCGen/HBC/BytecodeList.def"
766
1.41k
      ;
767
1.41k
#undef DEFINE_RET_TARGET
768
769
1.41k
  const uint8_t offset = static_cast<uint8_t>(ip->opCode) - firstCall;
770
1.41k
  return IPADD(((callSizes >> (offset * W)) & mask) + minSize);
771
1.41k
}
772
773
CallResult<HermesValue> Runtime::interpretFunctionImpl(
774
231
    CodeBlock *newCodeBlock) {
775
231
  if (LLVM_UNLIKELY(
776
231
          newCodeBlock->lazyCompile(*this) == ExecutionStatus::EXCEPTION)) {
777
0
    return ExecutionStatus::EXCEPTION;
778
0
  }
779
780
231
#if defined(HERMES_MEMORY_INSTRUMENTATION) || !defined(NDEBUG)
781
  // We always call getCurrentIP() in a debug build as this has the effect
782
  // of asserting the IP is correctly set (not invalidated) at this point.
783
  // This allows us to leverage our whole test-suite to find missing cases
784
  // of CAPTURE_IP* macros in the interpreter loop.
785
231
  const inst::Inst *ip = getCurrentIP();
786
231
  (void)ip;
787
231
#endif
788
231
#ifdef HERMES_MEMORY_INSTRUMENTATION
789
231
  if (ip) {
790
80
    const CodeBlock *codeBlock;
791
80
    std::tie(codeBlock, ip) = getCurrentInterpreterLocation(ip);
792
    // All functions end in a Ret so we must match this with a pushCallStack()
793
    // before executing.
794
80
    if (codeBlock) {
795
      // Push a call entry at the last location we were executing bytecode.
796
      // This will correctly attribute things like eval().
797
80
      pushCallStack(codeBlock, ip);
798
80
    } else {
799
      // Push a call entry at the entry at the top of interpreted code.
800
0
      pushCallStack(newCodeBlock, (const Inst *)newCodeBlock->begin());
801
0
    }
802
151
  } else {
803
    // Push a call entry at the entry at the top of interpreted code.
804
151
    pushCallStack(newCodeBlock, (const Inst *)newCodeBlock->begin());
805
151
  }
806
231
#endif
807
808
231
  InterpreterState state{newCodeBlock, 0};
809
231
  if (HERMESVM_CRASH_TRACE &&
810
0
      (getVMExperimentFlags() & experiments::CrashTrace)) {
811
0
    return Interpreter::interpretFunction<false, true>(*this, state);
812
231
  } else {
813
231
    return Interpreter::interpretFunction<false, false>(*this, state);
814
231
  }
815
231
}
816
817
231
CallResult<HermesValue> Runtime::interpretFunction(CodeBlock *newCodeBlock) {
818
  // Make sure we are not re-entering JS execution from a context that doesn't
819
  // allow reentrancy
820
231
  assert(this->noRJSLevel_ == 0 && "No JS execution allowed right now.");
821
231
  return interpretFunctionImpl(newCodeBlock);
822
231
}
823
824
#ifdef HERMES_ENABLE_DEBUGGER
825
0
ExecutionStatus Runtime::stepFunction(InterpreterState &state) {
826
0
  if (HERMESVM_CRASH_TRACE &&
827
0
      (getVMExperimentFlags() & experiments::CrashTrace))
828
0
    return Interpreter::interpretFunction<true, true>(*this, state).getStatus();
829
0
  else
830
0
    return Interpreter::interpretFunction<true, false>(*this, state)
831
0
        .getStatus();
832
0
}
833
#endif
834
835
template <bool SingleStep, bool EnableCrashTrace>
836
CallResult<HermesValue> Interpreter::interpretFunction(
837
    Runtime &runtime,
838
231
    InterpreterState &state) {
839
  // The interpreter is re-entrant and also saves/restores its IP via the
840
  // runtime whenever a call out is made (see the CAPTURE_IP_* macros). As such,
841
  // failure to preserve the IP across calls to interpreterFunction() disrupt
842
  // interpreter calls further up the C++ callstack. The RAII utility class
843
  // below makes sure we always do this correctly.
844
  //
845
  // TODO: The IPs stored in the C++ callstack via this holder will generally be
846
  // the same as in the JS stack frames via the Saved IP field. We can probably
847
  // get rid of one of these redundant stores. Doing this isn't completely
848
  // trivial as there are currently cases where we re-enter the interpreter
849
  // without calling Runtime::saveCallerIPInStackFrame(), and there are features
850
  // (I think mostly the debugger + stack traces) which implicitly rely on
851
  // this behavior. At least their tests break if this behavior is not
852
  // preserved.
853
231
  struct IPSaver {
854
231
    IPSaver(Runtime &runtime)
855
231
        : ip_(runtime.getCurrentIP()), runtime_(runtime) {}
hermes::vm::Interpreter::interpretFunction<false, false>(hermes::vm::Runtime&, hermes::vm::InterpreterState&)::IPSaver::IPSaver(hermes::vm::Runtime&)
Line
Count
Source
855
231
        : ip_(runtime.getCurrentIP()), runtime_(runtime) {}
Unexecuted instantiation: hermes::vm::Interpreter::interpretFunction<true, false>(hermes::vm::Runtime&, hermes::vm::InterpreterState&)::IPSaver::IPSaver(hermes::vm::Runtime&)
856
857
231
    ~IPSaver() {
858
231
      runtime_.setCurrentIP(ip_);
859
231
    }
hermes::vm::Interpreter::interpretFunction<false, false>(hermes::vm::Runtime&, hermes::vm::InterpreterState&)::IPSaver::~IPSaver()
Line
Count
Source
857
231
    ~IPSaver() {
858
231
      runtime_.setCurrentIP(ip_);
859
231
    }
Unexecuted instantiation: hermes::vm::Interpreter::interpretFunction<true, false>(hermes::vm::Runtime&, hermes::vm::InterpreterState&)::IPSaver::~IPSaver()
860
861
231
   private:
862
231
    const Inst *ip_;
863
231
    Runtime &runtime_;
864
231
  };
865
231
  IPSaver ipSaver(runtime);
866
867
#ifndef HERMES_ENABLE_DEBUGGER
868
  static_assert(!SingleStep, "can't use single-step mode without the debugger");
869
#endif
870
  // Make sure that the cache can use an optimization by avoiding a branch to
871
  // access the property storage.
872
231
  static_assert(
873
231
      HiddenClass::kDictionaryThreshold <=
874
231
          SegmentedArray::kValueToSegmentThreshold,
875
231
      "Cannot avoid branches in cache check if the dictionary "
876
231
      "crossover point is larger than the inline storage");
877
878
231
  CodeBlock *curCodeBlock = state.codeBlock;
879
231
  const Inst *ip = nullptr;
880
  // Points to the first local register in the current frame.
881
  // This eliminates the indirect load from Runtime and the -1 offset.
882
231
  PinnedHermesValue *frameRegs;
883
  // Strictness of current function.
884
231
  bool strictMode;
885
  // Default flags when accessing properties.
886
231
  PropOpFlags defaultPropOpFlags;
887
888
// These CAPTURE_IP* macros should wrap around any major calls out of the
889
// interpreter loop. They stash and retrieve the IP via the current Runtime
890
// allowing the IP to be externally observed and even altered to change the flow
891
// of execution. Explicitly saving AND restoring the IP from the Runtime in this
892
// way means the C++ compiler will keep IP in a register within the rest of the
893
// interpreter loop.
894
//
895
// When assertions are enabled we take the extra step of "invalidating" the IP
896
// between captures so we can detect if it's erroneously accessed.
897
//
898
#ifdef NDEBUG
899
900
#define CAPTURE_IP(expr)    \
901
  runtime.setCurrentIP(ip); \
902
  (void)(expr);             \
903
  ip = runtime.getCurrentIP();
904
905
// Used when we want to declare a new variable and assign the expression to it.
906
#define CAPTURE_IP_ASSIGN(decl, expr) \
907
  runtime.setCurrentIP(ip);           \
908
  decl = (expr);                      \
909
  ip = runtime.getCurrentIP();
910
911
#else // !NDEBUG
912
913
231
#define CAPTURE_IP(expr)       \
914
2.10M
  runtime.setCurrentIP(ip);    \
915
2.10M
  (void)(expr);                \
916
2.10M
  ip = runtime.getCurrentIP(); \
917
2.10M
  runtime.invalidateCurrentIP();
918
919
// Used when we want to declare a new variable and assign the expression to it.
920
231
#define CAPTURE_IP_ASSIGN(decl, expr) \
921
3.60M
  runtime.setCurrentIP(ip);           \
922
3.60M
  decl = (expr);                      \
923
3.60M
  ip = runtime.getCurrentIP();        \
924
3.60M
  runtime.invalidateCurrentIP();
925
926
231
#endif // NDEBUG
927
928
/// \def DONT_CAPTURE_IP(expr)
929
/// \param expr A call expression to a function external to the interpreter. The
930
///   expression should not make any allocations and the IP should be set
931
///   immediately following this macro.
932
231
#define DONT_CAPTURE_IP(expr)      \
933
231
  do {                             \
934
0
    NoAllocScope noAlloc(runtime); \
935
0
    (void)expr;                    \
936
0
  } while (false)
937
938
// When performing a tail call, we need to set the runtime IP and leave it set.
939
1.41k
#define CAPTURE_IP_SET() runtime.setCurrentIP(ip)
940
941
231
  LLVM_DEBUG(dbgs() << "interpretFunction() called\n");
942
943
231
  ScopedNativeDepthTracker depthTracker{runtime};
944
231
  if (LLVM_UNLIKELY(depthTracker.overflowed())) {
945
0
    return runtime.raiseStackOverflow(Runtime::StackOverflowKind::NativeStack);
946
0
  }
947
948
231
  GCScope gcScope(runtime);
949
  // Avoid allocating a handle dynamically by reusing this one.
950
231
  MutableHandle<> tmpHandle(runtime);
951
231
  CallResult<HermesValue> res{ExecutionStatus::EXCEPTION};
952
231
  CallResult<PseudoHandle<>> resPH{ExecutionStatus::EXCEPTION};
953
231
  CallResult<Handle<Arguments>> resArgs{ExecutionStatus::EXCEPTION};
954
231
  CallResult<bool> boolRes{ExecutionStatus::EXCEPTION};
955
  // Start of the bytecode file, used to calculate IP offset in crash traces.
956
231
  const uint8_t *bytecodeFileStart;
957
958
  // Mark the gcScope so we can clear all allocated handles.
959
  // Remember how many handles the scope has so we can clear them in the loop.
960
231
  static constexpr unsigned KEEP_HANDLES = 1;
961
231
  assert(
962
231
      gcScope.getHandleCountDbg() == KEEP_HANDLES &&
963
231
      "scope has unexpected number of handles");
964
965
231
  INIT_OPCODE_PROFILER;
966
967
1.64k
tailCall:
968
1.64k
  PROFILER_ENTER_FUNCTION(curCodeBlock);
969
970
1.64k
#ifdef HERMES_ENABLE_DEBUGGER
971
1.64k
  runtime.getDebugger().willEnterCodeBlock(curCodeBlock);
972
1.64k
#endif
973
974
1.64k
  runtime.getCodeCoverageProfiler().markExecuted(curCodeBlock);
975
976
1.64k
  if (!SingleStep) {
977
1.64k
    auto newFrame = runtime.setCurrentFrameToTopOfStack();
978
1.64k
    runtime.saveCallerIPInStackFrame();
979
1.64k
#ifndef NDEBUG
980
1.64k
    runtime.invalidateCurrentIP();
981
1.64k
#endif
982
983
    // Point frameRegs to the first register in the new frame. Note that at this
984
    // moment technically it points above the top of the stack, but we are never
985
    // going to access it.
986
1.64k
    frameRegs = &newFrame.getFirstLocalRef();
987
988
1.64k
#ifndef NDEBUG
989
1.64k
    LLVM_DEBUG(
990
1.64k
        dbgs() << "function entry: stackLevel=" << runtime.getStackLevel()
991
1.64k
               << ", argCount=" << runtime.getCurrentFrame().getArgCount()
992
1.64k
               << ", frameSize=" << curCodeBlock->getFrameSize() << "\n");
993
994
1.64k
    LLVM_DEBUG(
995
1.64k
        dbgs() << " callee "
996
1.64k
               << DumpHermesValue(
997
1.64k
                      runtime.getCurrentFrame().getCalleeClosureOrCBRef())
998
1.64k
               << "\n");
999
1.64k
    LLVM_DEBUG(
1000
1.64k
        dbgs() << "   this "
1001
1.64k
               << DumpHermesValue(runtime.getCurrentFrame().getThisArgRef())
1002
1.64k
               << "\n");
1003
2.76k
    for (uint32_t i = 0; i != runtime.getCurrentFrame()->getArgCount(); ++i) {
1004
1.12k
      LLVM_DEBUG(
1005
1.12k
          dbgs() << "   " << llvh::format_decimal(i, 4) << " "
1006
1.12k
                 << DumpHermesValue(runtime.getCurrentFrame().getArgRef(i))
1007
1.12k
                 << "\n");
1008
1.12k
    }
1009
1.64k
#endif
1010
1011
    // Allocate the registers for the new frame.
1012
1.64k
    if (LLVM_UNLIKELY(!runtime.checkAndAllocStack(
1013
1.64k
            curCodeBlock->getFrameSize() +
1014
1.64k
                StackFrameLayout::CalleeExtraRegistersAtStart,
1015
1.64k
            HermesValue::encodeUndefinedValue())))
1016
0
      goto stackOverflow;
1017
1018
1.64k
    ip = (Inst const *)curCodeBlock->begin();
1019
1020
    // Check for invalid invocation.
1021
1.64k
    if (LLVM_UNLIKELY(curCodeBlock->getHeaderFlags().isCallProhibited(
1022
1.64k
            newFrame.isConstructorCall()))) {
1023
0
      if (!newFrame.isConstructorCall()) {
1024
0
        CAPTURE_IP(
1025
0
            runtime.raiseTypeError("Class constructor invoked without new"));
1026
0
      } else {
1027
0
        CAPTURE_IP(runtime.raiseTypeError("Function is not a constructor"));
1028
0
      }
1029
0
      goto handleExceptionInParent;
1030
0
    }
1031
1.64k
  } else {
1032
    // Point frameRegs to the first register in the frame.
1033
0
    frameRegs = &runtime.getCurrentFrame().getFirstLocalRef();
1034
0
    ip = (Inst const *)(curCodeBlock->begin() + state.offset);
1035
0
  }
1036
1037
1.64k
  assert((const uint8_t *)ip < curCodeBlock->end() && "CodeBlock is empty");
1038
1039
1.64k
  INIT_STATE_FOR_CODEBLOCK(curCodeBlock);
1040
1041
1.64k
#define BEFORE_OP_CODE                                                       \
1042
8.77M
  {                                                                          \
1043
8.77M
    UPDATE_OPCODE_TIME_SPENT;                                                \
1044
8.77M
    HERMES_SLOW_ASSERT(                                                      \
1045
8.77M
        curCodeBlock->contains(ip) && "curCodeBlock must contain ip");       \
1046
8.77M
    HERMES_SLOW_ASSERT((printDebugInfo(curCodeBlock, frameRegs, ip), true)); \
1047
8.25M
    HERMES_SLOW_ASSERT(                                                      \
1048
8.25M
        gcScope.getHandleCountDbg() == KEEP_HANDLES &&                       \
1049
8.25M
        "unaccounted handles were created");                                 \
1050
8.25M
    HERMES_SLOW_ASSERT(tmpHandle->isUndefined() && "tmpHandle not cleared"); \
1051
8.25M
    RECORD_OPCODE_START_TIME;                                                \
1052
8.25M
    INC_OPCODE_COUNT;                                                        \
1053
8.25M
    if (EnableCrashTrace) {                                                  \
1054
0
      runtime.crashTrace_.recordInst(                                        \
1055
0
          (uint32_t)((const uint8_t *)ip - bytecodeFileStart), ip->opCode);  \
1056
0
    }                                                                        \
1057
8.25M
  }
1058
1059
1.64k
#ifdef HERMESVM_INDIRECT_THREADING
1060
1.64k
  static void *opcodeDispatch[] = {
1061
315k
#define DEFINE_OPCODE(name) &&case_##name,
1062
1.64k
#include "hermes/BCGen/HBC/BytecodeList.def"
1063
1.64k
      &&case__last};
1064
1065
8.25M
#define CASE(name) case_##name:
1066
// For indirect threading, there is no way to specify a default, leave it as
1067
// an empty label.
1068
1.64k
#define DEFAULT_CASE
1069
1.64k
#define DISPATCH                                \
1070
8.77M
  BEFORE_OP_CODE;                               \
1071
8.24M
  if (SingleStep) {                             \
1072
0
    state.codeBlock = curCodeBlock;             \
1073
0
    state.offset = CUROFFSET;                   \
1074
0
    return HermesValue::encodeUndefinedValue(); \
1075
0
  }                                             \
1076
8.24M
  goto *opcodeDispatch[(unsigned)ip->opCode]
1077
1078
// Do nothing if we're not in a switch.
1079
1.64k
#define INTERPRETER_FALLTHROUGH
1080
1081
#else // HERMESVM_INDIRECT_THREADING
1082
1083
#define CASE(name) case OpCode::name:
1084
#define DEFAULT_CASE default:
1085
#define DISPATCH                                \
1086
  if (SingleStep) {                             \
1087
    state.codeBlock = curCodeBlock;             \
1088
    state.offset = CUROFFSET;                   \
1089
    return HermesValue::encodeUndefinedValue(); \
1090
  }                                             \
1091
  continue
1092
1093
// Fallthrough if we're in a switch.
1094
#define INTERPRETER_FALLTHROUGH [[fallthrough]]
1095
1096
#endif // HERMESVM_INDIRECT_THREADING
1097
1098
// This macro is used when we detect that either the Implicit or Explicit
1099
// AsyncBreak flags have been set. It checks to see which one was requested and
1100
// propagate the corresponding RunReason. If both Implicit and Explicit have
1101
// been requested, then we'll propagate the RunReasons for both. Once for
1102
// Implicit and once for Explicit.
1103
1.64k
#define RUN_DEBUGGER_ASYNC_BREAK(flags)                         \
1104
1.64k
  bool requestedImplicit = (uint8_t)(flags) &                   \
1105
0
      (uint8_t)Runtime::AsyncBreakReasonBits::DebuggerImplicit; \
1106
0
  bool requestedExplicit = (uint8_t)(flags) &                   \
1107
0
      (uint8_t)Runtime::AsyncBreakReasonBits::DebuggerExplicit; \
1108
0
  do {                                                          \
1109
0
    if (requestedImplicit) {                                    \
1110
0
      CAPTURE_IP_ASSIGN(                                        \
1111
0
          auto dRes,                                            \
1112
0
          runDebuggerUpdatingState(                             \
1113
0
              Debugger::RunReason::AsyncBreakImplicit,          \
1114
0
              runtime,                                          \
1115
0
              curCodeBlock,                                     \
1116
0
              ip,                                               \
1117
0
              frameRegs));                                      \
1118
0
      if (dRes == ExecutionStatus::EXCEPTION)                   \
1119
0
        goto exception;                                         \
1120
0
    }                                                           \
1121
0
    if (requestedExplicit) {                                    \
1122
0
      CAPTURE_IP_ASSIGN(                                        \
1123
0
          auto dRes,                                            \
1124
0
          runDebuggerUpdatingState(                             \
1125
0
              Debugger::RunReason::AsyncBreakExplicit,          \
1126
0
              runtime,                                          \
1127
0
              curCodeBlock,                                     \
1128
0
              ip,                                               \
1129
0
              frameRegs));                                      \
1130
0
      if (dRes == ExecutionStatus::EXCEPTION)                   \
1131
0
        goto exception;                                         \
1132
0
    }                                                           \
1133
0
  } while (0)
1134
1135
1.64k
  for (;;) {
1136
6.56k
    BEFORE_OP_CODE;
1137
1138
6.56k
#ifdef HERMESVM_INDIRECT_THREADING
1139
6.56k
    goto *opcodeDispatch[(unsigned)ip->opCode];
1140
#else
1141
    switch (ip->opCode)
1142
#endif
1143
6.56k
    {
1144
6.56k
      const Inst *nextIP;
1145
6.56k
      uint32_t idVal;
1146
6.56k
      bool tryProp;
1147
6.56k
      uint32_t callArgCount;
1148
      // This is HermesValue::getRaw(), since HermesValue cannot be assigned
1149
      // to. It is meant to be used only for very short durations, in the
1150
      // dispatch of call instructions, when there is definitely no possibility
1151
      // of a GC.
1152
6.56k
      HermesValue::RawType callNewTarget;
1153
1154
/// Handle an opcode \p name with an out-of-line implementation in a function
1155
///   ExecutionStatus caseName(
1156
///       Runtime &,
1157
///       PinnedHermesValue *frameRegs,
1158
///       Inst *ip)
1159
6.56k
#define CASE_OUTOFLINE(name)                                         \
1160
6.56k
  CASE(name) {                                                       \
1161
9
    CAPTURE_IP_ASSIGN(auto res, case##name(runtime, frameRegs, ip)); \
1162
9
    if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {          \
1163
0
      goto exception;                                                \
1164
0
    }                                                                \
1165
9
    gcScope.flushToSmallCount(KEEP_HANDLES);                         \
1166
9
    ip = NEXTINST(name);                                             \
1167
9
    DISPATCH;                                                        \
1168
9
  }
1169
1170
/// Implement a binary arithmetic instruction with a fast path where both
1171
/// operands are numbers.
1172
/// \param name the name of the instruction. The fast path case will have a
1173
///     "n" appended to the name.
1174
6.56k
#define BINOP(name)                                                      \
1175
6.56k
  CASE(name) {                                                           \
1176
124
    if (LLVM_LIKELY(O2REG(name).isNumber() && O3REG(name).isNumber())) { \
1177
      /* Fast-path. */                                                   \
1178
123
      INTERPRETER_FALLTHROUGH;                                           \
1179
123
      CASE(name##N) {                                                    \
1180
123
        O1REG(name) = HermesValue::encodeTrustedNumberValue(             \
1181
123
            do##name(O2REG(name).getNumber(), O3REG(name).getNumber())); \
1182
123
        ip = NEXTINST(name);                                             \
1183
615
        DISPATCH;                                                        \
1184
615
      }                                                                  \
1185
615
    }                                                                    \
1186
124
    CAPTURE_IP(                                                          \
1187
124
        res = doOperSlowPath<do##name>(                                  \
1188
124
            runtime, Handle<>(&O2REG(name)), Handle<>(&O3REG(name))));   \
1189
124
    if (res == ExecutionStatus::EXCEPTION)                               \
1190
124
      goto exception;                                                    \
1191
124
    O1REG(name) = *res;                                                  \
1192
124
    gcScope.flushToSmallCount(KEEP_HANDLES);                             \
1193
124
    ip = NEXTINST(name);                                                 \
1194
124
    DISPATCH;                                                            \
1195
1
  }
1196
1197
6.56k
#define INCDECOP(name)                                                        \
1198
6.56k
  CASE(name) {                                                                \
1199
0
    if (LLVM_LIKELY(O2REG(name).isNumber())) {                                \
1200
0
      O1REG(name) = HermesValue::encodeTrustedNumberValue(                    \
1201
0
          do##name(O2REG(name).getNumber()));                                 \
1202
0
      ip = NEXTINST(name);                                                    \
1203
0
      DISPATCH;                                                               \
1204
0
    }                                                                         \
1205
0
    CAPTURE_IP(                                                               \
1206
0
        res =                                                                 \
1207
0
            doIncDecOperSlowPath<do##name>(runtime, Handle<>(&O2REG(name)))); \
1208
0
    if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {                   \
1209
0
      goto exception;                                                         \
1210
0
    }                                                                         \
1211
0
    O1REG(name) = *res;                                                       \
1212
0
    gcScope.flushToSmallCount(KEEP_HANDLES);                                  \
1213
0
    ip = NEXTINST(name);                                                      \
1214
0
    DISPATCH;                                                                 \
1215
0
  }
1216
1217
/// Implement a shift instruction with a fast path where both
1218
/// operands are numbers.
1219
/// \param name the name of the instruction.
1220
6.56k
#define SHIFTOP(name)                                                          \
1221
6.56k
  CASE(name) {                                                                 \
1222
0
    if (LLVM_LIKELY(                                                           \
1223
0
            O2REG(name).isNumber() &&                                          \
1224
0
            O3REG(name).isNumber())) { /* Fast-path. */                        \
1225
0
      auto lnum = hermes::truncateToInt32(O2REG(name).getNumber());            \
1226
0
      uint32_t rnum = hermes::truncateToInt32(O3REG(name).getNumber()) & 0x1f; \
1227
0
      O1REG(name) =                                                            \
1228
0
          HermesValue::encodeTrustedNumberValue(do##name(lnum, rnum));         \
1229
0
      ip = NEXTINST(name);                                                     \
1230
0
      DISPATCH;                                                                \
1231
0
    }                                                                          \
1232
0
    CAPTURE_IP(                                                                \
1233
0
        res = doShiftOperSlowPath<do##name>(                                   \
1234
0
            runtime, Handle<>(&O2REG(name)), Handle<>(&O3REG(name))));         \
1235
0
    if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {                    \
1236
0
      goto exception;                                                          \
1237
0
    }                                                                          \
1238
0
    O1REG(name) = *res;                                                        \
1239
0
    gcScope.flushToSmallCount(KEEP_HANDLES);                                   \
1240
0
    ip = NEXTINST(name);                                                       \
1241
0
    DISPATCH;                                                                  \
1242
0
  }
1243
1244
/// Implement a binary bitwise instruction with a fast path where both
1245
/// operands are numbers.
1246
/// \param name the name of the instruction.
1247
6.56k
#define BITWISEBINOP(name)                                               \
1248
6.56k
  CASE(name) {                                                           \
1249
0
    if (LLVM_LIKELY(O2REG(name).isNumber() && O3REG(name).isNumber())) { \
1250
      /* Fast-path. */                                                   \
1251
0
      O1REG(name) = HermesValue::encodeTrustedNumberValue(               \
1252
0
          do##name(                                                      \
1253
0
              hermes::truncateToInt32(O2REG(name).getNumber()),          \
1254
0
              hermes::truncateToInt32(O3REG(name).getNumber())));        \
1255
0
      ip = NEXTINST(name);                                               \
1256
0
      DISPATCH;                                                          \
1257
0
    }                                                                    \
1258
0
    CAPTURE_IP(                                                          \
1259
0
        res = doBitOperSlowPath<do##name>(                               \
1260
0
            runtime, Handle<>(&O2REG(name)), Handle<>(&O3REG(name))));   \
1261
0
    if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {              \
1262
0
      goto exception;                                                    \
1263
0
    }                                                                    \
1264
0
    O1REG(name) = *res;                                                  \
1265
0
    gcScope.flushToSmallCount(KEEP_HANDLES);                             \
1266
0
    ip = NEXTINST(name);                                                 \
1267
0
    DISPATCH;                                                            \
1268
0
  }
1269
1270
/// Implement a comparison instruction.
1271
/// \param name the name of the instruction.
1272
/// \param oper the C++ operator to use to actually perform the fast arithmetic
1273
///     comparison.
1274
/// \param operFuncName  function to call for the slow-path comparison.
1275
6.56k
#define CONDOP(name, oper, operFuncName)                                 \
1276
511k
  CASE(name) {                                                           \
1277
511k
    if (LLVM_LIKELY(O2REG(name).isNumber() && O3REG(name).isNumber())) { \
1278
      /* Fast-path. */                                                   \
1279
0
      O1REG(name) = HermesValue::encodeBoolValue(                        \
1280
0
          O2REG(name).getNumber() oper O3REG(name).getNumber());         \
1281
0
      ip = NEXTINST(name);                                               \
1282
0
      DISPATCH;                                                          \
1283
0
    }                                                                    \
1284
511k
    CAPTURE_IP(                                                          \
1285
511k
        boolRes = operFuncName(                                          \
1286
511k
            runtime, Handle<>(&O2REG(name)), Handle<>(&O3REG(name))));   \
1287
511k
    if (boolRes == ExecutionStatus::EXCEPTION)                           \
1288
511k
      goto exception;                                                    \
1289
511k
    gcScope.flushToSmallCount(KEEP_HANDLES);                             \
1290
511k
    O1REG(name) = HermesValue::encodeBoolValue(boolRes.getValue());      \
1291
511k
    ip = NEXTINST(name);                                                 \
1292
511k
    DISPATCH;                                                            \
1293
511k
  }
1294
1295
/// Implement a comparison conditional jump with a fast path where both
1296
/// operands are numbers.
1297
/// \param name the name of the instruction. The fast path case will have a
1298
///     "N" appended to the name.
1299
/// \param suffix  Optional suffix to be added to the end (e.g. Long)
1300
/// \param oper the C++ operator to use to actually perform the fast arithmetic
1301
///     comparison.
1302
/// \param operFuncName  function to call for the slow-path comparison.
1303
/// \param trueDest  ip value if the conditional evaluates to true
1304
/// \param falseDest  ip value if the conditional evaluates to false
1305
6.56k
#define JCOND_IMPL(name, suffix, oper, operFuncName, trueDest, falseDest) \
1306
6.56k
  CASE(name##suffix) {                                                    \
1307
0
    if (LLVM_LIKELY(                                                      \
1308
0
            O2REG(name##suffix).isNumber() &&                             \
1309
0
            O3REG(name##suffix).isNumber())) {                            \
1310
      /* Fast-path. */                                                    \
1311
0
      INTERPRETER_FALLTHROUGH;                                            \
1312
0
      CASE(name##N##suffix) {                                             \
1313
0
        if (O2REG(name##N##suffix)                                        \
1314
0
                .getNumber() oper O3REG(name##N##suffix)                  \
1315
0
                .getNumber()) {                                           \
1316
0
          ip = trueDest;                                                  \
1317
0
          DISPATCH;                                                       \
1318
0
        }                                                                 \
1319
0
        ip = falseDest;                                                   \
1320
0
        DISPATCH;                                                         \
1321
0
      }                                                                   \
1322
0
    }                                                                     \
1323
0
    CAPTURE_IP(                                                           \
1324
0
        boolRes = operFuncName(                                           \
1325
0
            runtime,                                                      \
1326
0
            Handle<>(&O2REG(name##suffix)),                               \
1327
0
            Handle<>(&O3REG(name##suffix))));                             \
1328
0
    if (boolRes == ExecutionStatus::EXCEPTION)                            \
1329
0
      goto exception;                                                     \
1330
0
    gcScope.flushToSmallCount(KEEP_HANDLES);                              \
1331
0
    if (boolRes.getValue()) {                                             \
1332
0
      ip = trueDest;                                                      \
1333
0
      DISPATCH;                                                           \
1334
0
    }                                                                     \
1335
0
    ip = falseDest;                                                       \
1336
0
    DISPATCH;                                                             \
1337
0
  }
1338
1339
/// Implement a strict equality conditional jump
1340
/// \param name the name of the instruction.
1341
/// \param suffix  Optional suffix to be added to the end (e.g. Long)
1342
/// \param trueDest  ip value if the conditional evaluates to true
1343
/// \param falseDest  ip value if the conditional evaluates to false
1344
6.56k
#define JCOND_STRICT_EQ_IMPL(name, suffix, trueDest, falseDest)         \
1345
6.56k
  CASE(name##suffix) {                                                  \
1346
1.69k
    if (strictEqualityTest(O2REG(name##suffix), O3REG(name##suffix))) { \
1347
1.69k
      ip = trueDest;                                                    \
1348
8.46k
      DISPATCH;                                                         \
1349
8.46k
    }                                                                   \
1350
1.69k
    ip = falseDest;                                                     \
1351
1.69k
    DISPATCH;                                                           \
1352
0
  }
1353
1354
/// Implement an equality conditional jump
1355
/// \param name the name of the instruction.
1356
/// \param suffix  Optional suffix to be added to the end (e.g. Long)
1357
/// \param trueDest  ip value if the conditional evaluates to true
1358
/// \param falseDest  ip value if the conditional evaluates to false
1359
6.56k
#define JCOND_EQ_IMPL(name, suffix, trueDest, falseDest) \
1360
6.56k
  CASE(name##suffix) {                                   \
1361
188
    CAPTURE_IP_ASSIGN(                                   \
1362
188
        auto eqRes,                                      \
1363
188
        abstractEqualityTest_RJS(                        \
1364
188
            runtime,                                     \
1365
188
            Handle<>(&O2REG(name##suffix)),              \
1366
188
            Handle<>(&O3REG(name##suffix))));            \
1367
188
    if (eqRes == ExecutionStatus::EXCEPTION) {           \
1368
0
      goto exception;                                    \
1369
0
    }                                                    \
1370
188
    gcScope.flushToSmallCount(KEEP_HANDLES);             \
1371
188
    if (*eqRes) {                                        \
1372
0
      ip = trueDest;                                     \
1373
0
      DISPATCH;                                          \
1374
0
    }                                                    \
1375
188
    ip = falseDest;                                      \
1376
188
    DISPATCH;                                            \
1377
188
  }
1378
1379
/// Implement the long and short forms of a conditional jump, and its negation.
1380
6.56k
#define JCOND(name, oper, operFuncName) \
1381
6.56k
  JCOND_IMPL(                           \
1382
0
      J##name,                          \
1383
0
      ,                                 \
1384
0
      oper,                             \
1385
0
      operFuncName,                     \
1386
0
      IPADD(ip->iJ##name.op1),          \
1387
0
      NEXTINST(J##name));               \
1388
0
  JCOND_IMPL(                           \
1389
0
      J##name,                          \
1390
0
      Long,                             \
1391
0
      oper,                             \
1392
0
      operFuncName,                     \
1393
0
      IPADD(ip->iJ##name##Long.op1),    \
1394
0
      NEXTINST(J##name##Long));         \
1395
0
  JCOND_IMPL(                           \
1396
0
      JNot##name,                       \
1397
0
      ,                                 \
1398
0
      oper,                             \
1399
0
      operFuncName,                     \
1400
0
      NEXTINST(JNot##name),             \
1401
0
      IPADD(ip->iJNot##name.op1));      \
1402
0
  JCOND_IMPL(                           \
1403
0
      JNot##name,                       \
1404
0
      Long,                             \
1405
0
      oper,                             \
1406
0
      operFuncName,                     \
1407
0
      NEXTINST(JNot##name##Long),       \
1408
0
      IPADD(ip->iJNot##name##Long.op1));
1409
1410
/// Load a constant.
1411
/// \param value is the value to store in the output register.
1412
6.56k
#define LOAD_CONST(name, value) \
1413
1.05M
  CASE(name) {                  \
1414
1.05M
    O1REG(name) = value;        \
1415
1.05M
    ip = NEXTINST(name);        \
1416
1.05M
    DISPATCH;                   \
1417
1.05M
  }
1418
1419
6.56k
#define LOAD_CONST_CAPTURE_IP(name, value) \
1420
634k
  CASE(name) {                             \
1421
634k
    CAPTURE_IP(O1REG(name) = value);       \
1422
634k
    ip = NEXTINST(name);                   \
1423
634k
    DISPATCH;                              \
1424
634k
  }
1425
1426
1.02M
      CASE(Mov) {
1427
1.02M
        O1REG(Mov) = O2REG(Mov);
1428
1.02M
        ip = NEXTINST(Mov);
1429
5.12M
        DISPATCH;
1430
5.12M
      }
1431
1432
467k
      CASE(MovLong) {
1433
467k
        O1REG(MovLong) = O2REG(MovLong);
1434
467k
        ip = NEXTINST(MovLong);
1435
2.33M
        DISPATCH;
1436
2.33M
      }
1437
1438
1.69k
      CASE(LoadParam) {
1439
1.69k
        if (LLVM_LIKELY(ip->iLoadParam.op2 <= FRAME.getArgCount())) {
1440
          // index 0 must load 'this'. Index 1 the first argument, etc.
1441
1.69k
          O1REG(LoadParam) = FRAME.getArgRef((int32_t)ip->iLoadParam.op2 - 1);
1442
1.69k
          ip = NEXTINST(LoadParam);
1443
8.46k
          DISPATCH;
1444
8.46k
        }
1445
1.69k
        O1REG(LoadParam) = HermesValue::encodeUndefinedValue();
1446
1.69k
        ip = NEXTINST(LoadParam);
1447
1.69k
        DISPATCH;
1448
0
      }
1449
1450
0
      CASE(LoadParamLong) {
1451
0
        if (LLVM_LIKELY(ip->iLoadParamLong.op2 <= FRAME.getArgCount())) {
1452
          // index 0 must load 'this'. Index 1 the first argument, etc.
1453
0
          O1REG(LoadParamLong) =
1454
0
              FRAME.getArgRef((int32_t)ip->iLoadParamLong.op2 - 1);
1455
0
          ip = NEXTINST(LoadParamLong);
1456
0
          DISPATCH;
1457
0
        }
1458
0
        O1REG(LoadParamLong) = HermesValue::encodeUndefinedValue();
1459
0
        ip = NEXTINST(LoadParamLong);
1460
0
        DISPATCH;
1461
0
      }
1462
1463
0
      CASE(CoerceThisNS) {
1464
0
        if (LLVM_LIKELY(O2REG(CoerceThisNS).isObject())) {
1465
0
          O1REG(CoerceThisNS) = O2REG(CoerceThisNS);
1466
0
        } else if (
1467
0
            O2REG(CoerceThisNS).isNull() || O2REG(CoerceThisNS).isUndefined()) {
1468
0
          O1REG(CoerceThisNS) = runtime.global_;
1469
0
        } else {
1470
0
          tmpHandle = O2REG(CoerceThisNS);
1471
0
          nextIP = NEXTINST(CoerceThisNS);
1472
0
          goto coerceThisSlowPath;
1473
0
        }
1474
0
        ip = NEXTINST(CoerceThisNS);
1475
0
        DISPATCH;
1476
0
      }
1477
9
      CASE(LoadThisNS) {
1478
9
        if (LLVM_LIKELY(FRAME.getThisArgRef().isObject())) {
1479
9
          O1REG(LoadThisNS) = FRAME.getThisArgRef();
1480
9
        } else if (
1481
0
            FRAME.getThisArgRef().isNull() ||
1482
0
            FRAME.getThisArgRef().isUndefined()) {
1483
0
          O1REG(LoadThisNS) = runtime.global_;
1484
0
        } else {
1485
0
          tmpHandle = FRAME.getThisArgRef();
1486
0
          nextIP = NEXTINST(LoadThisNS);
1487
0
          goto coerceThisSlowPath;
1488
0
        }
1489
9
        ip = NEXTINST(LoadThisNS);
1490
45
        DISPATCH;
1491
45
      }
1492
0
    coerceThisSlowPath: {
1493
0
      CAPTURE_IP(res = toObject(runtime, tmpHandle));
1494
0
      if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
1495
0
        goto exception;
1496
0
      }
1497
0
      O1REG(CoerceThisNS) = res.getValue();
1498
0
      tmpHandle.clear();
1499
0
      gcScope.flushToSmallCount(KEEP_HANDLES);
1500
0
      ip = nextIP;
1501
0
      DISPATCH;
1502
0
    }
1503
1504
0
      CASE(ConstructLong) {
1505
0
        callArgCount = (uint32_t)ip->iConstructLong.op3;
1506
0
        nextIP = NEXTINST(ConstructLong);
1507
0
        callNewTarget = O2REG(ConstructLong).getRaw();
1508
0
        goto doCall;
1509
0
      }
1510
7
      CASE(CallLong) {
1511
7
        callArgCount = (uint32_t)ip->iCallLong.op3;
1512
7
        nextIP = NEXTINST(CallLong);
1513
7
        callNewTarget = HermesValue::encodeUndefinedValue().getRaw();
1514
7
        goto doCall;
1515
0
      }
1516
1517
      // Note in Call1 through Call4, the first argument is 'this' which has
1518
      // argument index -1.
1519
      // Also note that we are writing to callNewTarget last, to avoid the
1520
      // possibility of it being aliased by the arg writes.
1521
658
      CASE(Call1) {
1522
658
        callArgCount = 1;
1523
658
        nextIP = NEXTINST(Call1);
1524
658
        StackFramePtr fr{runtime.stackPointer_};
1525
658
        fr.getArgRefUnsafe(-1) = O3REG(Call1);
1526
658
        callNewTarget = HermesValue::encodeUndefinedValue().getRaw();
1527
658
        goto doCall;
1528
0
      }
1529
1530
752
      CASE(Call2) {
1531
752
        callArgCount = 2;
1532
752
        nextIP = NEXTINST(Call2);
1533
752
        StackFramePtr fr{runtime.stackPointer_};
1534
752
        fr.getArgRefUnsafe(-1) = O3REG(Call2);
1535
752
        fr.getArgRefUnsafe(0) = O4REG(Call2);
1536
752
        callNewTarget = HermesValue::encodeUndefinedValue().getRaw();
1537
752
        goto doCall;
1538
0
      }
1539
1540
0
      CASE(Call3) {
1541
0
        callArgCount = 3;
1542
0
        nextIP = NEXTINST(Call3);
1543
0
        StackFramePtr fr{runtime.stackPointer_};
1544
0
        fr.getArgRefUnsafe(-1) = O3REG(Call3);
1545
0
        fr.getArgRefUnsafe(0) = O4REG(Call3);
1546
0
        fr.getArgRefUnsafe(1) = O5REG(Call3);
1547
0
        callNewTarget = HermesValue::encodeUndefinedValue().getRaw();
1548
0
        goto doCall;
1549
0
      }
1550
1551
0
      CASE(Call4) {
1552
0
        callArgCount = 4;
1553
0
        nextIP = NEXTINST(Call4);
1554
0
        StackFramePtr fr{runtime.stackPointer_};
1555
0
        fr.getArgRefUnsafe(-1) = O3REG(Call4);
1556
0
        fr.getArgRefUnsafe(0) = O4REG(Call4);
1557
0
        fr.getArgRefUnsafe(1) = O5REG(Call4);
1558
0
        fr.getArgRefUnsafe(2) = O6REG(Call4);
1559
0
        callNewTarget = HermesValue::encodeUndefinedValue().getRaw();
1560
0
        goto doCall;
1561
0
      }
1562
1563
564
      CASE(Construct) {
1564
564
        callArgCount = (uint32_t)ip->iConstruct.op3;
1565
564
        nextIP = NEXTINST(Construct);
1566
564
        callNewTarget = O2REG(Construct).getRaw();
1567
564
        goto doCall;
1568
0
      }
1569
86
      CASE(Call) {
1570
86
        callArgCount = (uint32_t)ip->iCall.op3;
1571
86
        nextIP = NEXTINST(Call);
1572
86
        callNewTarget = HermesValue::encodeUndefinedValue().getRaw();
1573
86
        goto doCall;
1574
0
      }
1575
1576
2.06k
    doCall: {
1577
2.06k
#ifdef HERMES_ENABLE_DEBUGGER
1578
      // Check for an async debugger request.
1579
2.06k
      if (uint8_t asyncFlags =
1580
2.06k
              runtime.testAndClearDebuggerAsyncBreakRequest()) {
1581
0
        RUN_DEBUGGER_ASYNC_BREAK(asyncFlags);
1582
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
1583
0
        DISPATCH;
1584
0
      }
1585
2.06k
#endif
1586
1587
      // Subtract 1 from callArgCount as 'this' is considered an argument in the
1588
      // instruction, but not in the frame.
1589
2.06k
      auto newFrame = StackFramePtr::initFrame(
1590
2.06k
          runtime.stackPointer_,
1591
2.06k
          FRAME,
1592
2.06k
          ip,
1593
2.06k
          curCodeBlock,
1594
2.06k
          callArgCount - 1,
1595
2.06k
          O2REG(Call),
1596
2.06k
          HermesValue::fromRaw(callNewTarget));
1597
2.06k
      (void)newFrame;
1598
1599
2.06k
      SLOW_DEBUG(dumpCallArguments(dbgs(), runtime, newFrame));
1600
1601
2.06k
      if (auto *func = dyn_vmcast<JSFunction>(O2REG(Call))) {
1602
1.41k
        assert(!SingleStep && "can't single-step a call");
1603
1604
1.41k
#ifdef HERMES_MEMORY_INSTRUMENTATION
1605
1.41k
        runtime.pushCallStack(curCodeBlock, ip);
1606
1.41k
#endif
1607
1608
1.41k
        CodeBlock *calleeBlock = func->getCodeBlock(runtime);
1609
1.41k
        CAPTURE_IP_ASSIGN(auto res, calleeBlock->lazyCompile(runtime));
1610
1.41k
        if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
1611
0
          goto exception;
1612
0
        }
1613
1.41k
        curCodeBlock = calleeBlock;
1614
1.41k
        CAPTURE_IP_SET();
1615
1.41k
        goto tailCall;
1616
1.41k
      }
1617
657
      CAPTURE_IP(
1618
657
          resPH = Interpreter::handleCallSlowPath(runtime, &O2REG(Call)));
1619
657
      if (LLVM_UNLIKELY(resPH == ExecutionStatus::EXCEPTION)) {
1620
5
        goto exception;
1621
5
      }
1622
652
      O1REG(Call) = std::move(resPH->get());
1623
652
      SLOW_DEBUG(
1624
652
          dbgs() << "native return value r" << (unsigned)ip->iCall.op1 << "="
1625
652
                 << DumpHermesValue(O1REG(Call)) << "\n");
1626
652
      gcScope.flushToSmallCount(KEEP_HANDLES);
1627
652
      ip = nextIP;
1628
3.26k
      DISPATCH;
1629
3.26k
    }
1630
1631
0
      CASE(CallDirect)
1632
0
      CASE(CallDirectLongIndex) {
1633
0
#ifdef HERMES_ENABLE_DEBUGGER
1634
        // Check for an async debugger request.
1635
0
        if (uint8_t asyncFlags =
1636
0
                runtime.testAndClearDebuggerAsyncBreakRequest()) {
1637
0
          RUN_DEBUGGER_ASYNC_BREAK(asyncFlags);
1638
0
          gcScope.flushToSmallCount(KEEP_HANDLES);
1639
0
          DISPATCH;
1640
0
        }
1641
0
#endif
1642
1643
0
        CAPTURE_IP_ASSIGN(
1644
0
            CodeBlock * calleeBlock,
1645
0
            ip->opCode == OpCode::CallDirect
1646
0
                ? curCodeBlock->getRuntimeModule()->getCodeBlockMayAllocate(
1647
0
                      ip->iCallDirect.op3)
1648
0
                : curCodeBlock->getRuntimeModule()->getCodeBlockMayAllocate(
1649
0
                      ip->iCallDirectLongIndex.op3));
1650
1651
0
        auto newFrame = StackFramePtr::initFrame(
1652
0
            runtime.stackPointer_,
1653
0
            FRAME,
1654
0
            ip,
1655
0
            curCodeBlock,
1656
0
            (uint32_t)ip->iCallDirect.op2 - 1,
1657
0
            HermesValue::encodeNativePointer(calleeBlock),
1658
0
            HermesValue::encodeUndefinedValue());
1659
0
        (void)newFrame;
1660
1661
0
        LLVM_DEBUG(dumpCallArguments(dbgs(), runtime, newFrame));
1662
1663
0
        assert(!SingleStep && "can't single-step a call");
1664
1665
0
        CAPTURE_IP_ASSIGN(auto res, calleeBlock->lazyCompile(runtime));
1666
0
        if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
1667
0
          goto exception;
1668
0
        }
1669
0
        curCodeBlock = calleeBlock;
1670
0
        CAPTURE_IP_SET();
1671
0
        goto tailCall;
1672
0
      }
1673
1674
0
      CASE(GetBuiltinClosure) {
1675
0
        uint8_t methodIndex = ip->iCallBuiltin.op2;
1676
0
        Callable *closure = runtime.getBuiltinCallable(methodIndex);
1677
0
        O1REG(GetBuiltinClosure) = HermesValue::encodeObjectValue(closure);
1678
0
        ip = NEXTINST(GetBuiltinClosure);
1679
0
        DISPATCH;
1680
0
      }
1681
1682
105
      CASE(CallBuiltin) {
1683
105
        CAPTURE_IP_ASSIGN(
1684
105
            auto cres,
1685
105
            implCallBuiltin(
1686
105
                runtime, frameRegs, curCodeBlock, ip->iCallBuiltin.op3));
1687
105
        if (LLVM_UNLIKELY(cres == ExecutionStatus::EXCEPTION))
1688
0
          goto exception;
1689
105
        gcScope.flushToSmallCount(KEEP_HANDLES);
1690
105
        ip = NEXTINST(CallBuiltin);
1691
525
        DISPATCH;
1692
525
      }
1693
7
      CASE(CallBuiltinLong) {
1694
7
        CAPTURE_IP_ASSIGN(
1695
7
            auto cres,
1696
7
            implCallBuiltin(
1697
7
                runtime, frameRegs, curCodeBlock, ip->iCallBuiltinLong.op3));
1698
7
        if (LLVM_UNLIKELY(cres == ExecutionStatus::EXCEPTION))
1699
0
          goto exception;
1700
7
        gcScope.flushToSmallCount(KEEP_HANDLES);
1701
7
        ip = NEXTINST(CallBuiltinLong);
1702
35
        DISPATCH;
1703
35
      }
1704
1705
0
      CASE(CompleteGenerator) {
1706
0
        auto *innerFn = vmcast<GeneratorInnerFunction>(
1707
0
            runtime.getCurrentFrame().getCalleeClosureUnsafe());
1708
0
        innerFn->setState(GeneratorInnerFunction::State::Completed);
1709
0
        ip = NEXTINST(CompleteGenerator);
1710
0
        DISPATCH;
1711
0
      }
1712
1713
0
      CASE(SaveGenerator) {
1714
0
        DONT_CAPTURE_IP(
1715
0
            saveGenerator(runtime, frameRegs, IPADD(ip->iSaveGenerator.op1)));
1716
0
        ip = NEXTINST(SaveGenerator);
1717
0
        DISPATCH;
1718
0
      }
1719
0
      CASE(SaveGeneratorLong) {
1720
0
        DONT_CAPTURE_IP(saveGenerator(
1721
0
            runtime, frameRegs, IPADD(ip->iSaveGeneratorLong.op1)));
1722
0
        ip = NEXTINST(SaveGeneratorLong);
1723
0
        DISPATCH;
1724
0
      }
1725
1726
0
      CASE(StartGenerator) {
1727
0
        auto *innerFn = vmcast<GeneratorInnerFunction>(
1728
0
            runtime.getCurrentFrame().getCalleeClosureUnsafe());
1729
0
        if (innerFn->getState() ==
1730
0
            GeneratorInnerFunction::State::SuspendedStart) {
1731
0
          nextIP = NEXTINST(StartGenerator);
1732
0
        } else {
1733
0
          nextIP = innerFn->getNextIP(runtime);
1734
0
          innerFn->restoreStack(runtime);
1735
0
        }
1736
0
        innerFn->setState(GeneratorInnerFunction::State::Executing);
1737
0
        ip = nextIP;
1738
0
        DISPATCH;
1739
0
      }
1740
1741
0
      CASE(ResumeGenerator) {
1742
0
        auto *innerFn = vmcast<GeneratorInnerFunction>(
1743
0
            runtime.getCurrentFrame().getCalleeClosureUnsafe());
1744
0
        O2REG(ResumeGenerator) = HermesValue::encodeBoolValue(
1745
0
            innerFn->getAction() == GeneratorInnerFunction::Action::Return);
1746
        // Write the result last in case it is the same register as O2REG.
1747
0
        O1REG(ResumeGenerator) = innerFn->getResult().unboxToHV(runtime);
1748
0
        innerFn->clearResult(runtime);
1749
0
        if (innerFn->getAction() == GeneratorInnerFunction::Action::Throw) {
1750
0
          runtime.setThrownValue(O1REG(ResumeGenerator));
1751
0
          goto exception;
1752
0
        }
1753
0
        ip = NEXTINST(ResumeGenerator);
1754
0
        DISPATCH;
1755
0
      }
1756
1757
1.61k
      CASE(Ret) {
1758
1.61k
#ifdef HERMES_ENABLE_DEBUGGER
1759
        // Check for an async debugger request, but skip it if we're single
1760
        // stepping. The only case where we'd be single stepping a Ret is if it
1761
        // was replaced with Debugger OpCode and we're coming here from
1762
        // stepFunction(). This does take away a chance to handle AsyncBreak. An
1763
        // AsyncBreak request could be either Explicit or Implicit. The Explicit
1764
        // case is to have the program being executed to pause. There isn't a
1765
        // need to pause at a particular location. Also, since we just came from
1766
        // a breakpoint, handling Explicit AsyncBreak for single step isn't so
1767
        // important. The other possible kind is an Implicit AsyncBreak, which
1768
        // is used for debug clients to interrupt the runtime to execute their
1769
        // own code. Not processing AsyncBreak just means that the Implicit
1770
        // AsyncBreak needs to wait for the next opportunity to interrupt the
1771
        // runtime, which should be fine. There is no contract for when the
1772
        // interrupt should happen.
1773
1.61k
        if (!SingleStep) {
1774
1.61k
          if (uint8_t asyncFlags =
1775
1.61k
                  runtime.testAndClearDebuggerAsyncBreakRequest()) {
1776
0
            RUN_DEBUGGER_ASYNC_BREAK(asyncFlags);
1777
0
            gcScope.flushToSmallCount(KEEP_HANDLES);
1778
0
            DISPATCH;
1779
0
          }
1780
1.61k
        }
1781
1.61k
#endif
1782
1783
1.61k
        PROFILER_EXIT_FUNCTION(curCodeBlock);
1784
1785
1.61k
#ifdef HERMES_MEMORY_INSTRUMENTATION
1786
1.61k
        runtime.popCallStack();
1787
1.61k
#endif
1788
1789
        // Store the return value.
1790
1.61k
        res = O1REG(Ret);
1791
1792
1.61k
        ip = FRAME.getSavedIP();
1793
1.61k
        curCodeBlock = FRAME.getSavedCodeBlock();
1794
1795
1.61k
        frameRegs =
1796
1.61k
            &runtime.restoreStackAndPreviousFrame(FRAME).getFirstLocalRef();
1797
1798
1.61k
        SLOW_DEBUG(
1799
1.61k
            dbgs() << "function exit: restored stackLevel="
1800
1.61k
                   << runtime.getStackLevel() << "\n");
1801
1802
        // Are we returning to native code?
1803
1.61k
        if (!curCodeBlock) {
1804
201
          SLOW_DEBUG(dbgs() << "function exit: returning to native code\n");
1805
201
          return res;
1806
201
        }
1807
1808
1.41k
        INIT_STATE_FOR_CODEBLOCK(curCodeBlock);
1809
1.41k
        O1REG(Call) = res.getValue();
1810
1811
1.41k
#ifdef HERMES_ENABLE_DEBUGGER
1812
        // Only do the more expensive check for breakpoint location (in
1813
        // getRealOpCode) if there are breakpoints installed in the function
1814
        // we're returning into.
1815
1.41k
        if (LLVM_UNLIKELY(curCodeBlock->getNumInstalledBreakpoints() > 0)) {
1816
0
          ip = IPADD(
1817
0
              inst::getInstSize(
1818
0
                  runtime.debugger_.getRealOpCode(curCodeBlock, CUROFFSET)));
1819
1.41k
        } else {
1820
          // No breakpoints in the function being returned to, just use
1821
          // nextInstCall().
1822
1.41k
          ip = nextInstCall(ip);
1823
1.41k
        }
1824
#else
1825
        ip = nextInstCall(ip);
1826
#endif
1827
1828
7.05k
        DISPATCH;
1829
7.05k
      }
1830
1831
0
      CASE(Catch) {
1832
0
        assert(!runtime.thrownValue_.isEmpty() && "Invalid thrown value");
1833
0
        assert(
1834
0
            !isUncatchableError(runtime.thrownValue_) &&
1835
0
            "Uncatchable thrown value was caught");
1836
0
        O1REG(Catch) = runtime.thrownValue_;
1837
0
        runtime.clearThrownValue();
1838
0
#ifdef HERMES_ENABLE_DEBUGGER
1839
        // Signal to the debugger that we're done unwinding an exception,
1840
        // and we can resume normal debugging flow.
1841
0
        runtime.debugger_.finishedUnwindingException();
1842
0
#endif
1843
0
        ip = NEXTINST(Catch);
1844
0
        DISPATCH;
1845
0
      }
1846
1847
0
      CASE(Throw) {
1848
0
        runtime.thrownValue_ = O1REG(Throw);
1849
0
        SLOW_DEBUG(
1850
0
            dbgs() << "Exception thrown: "
1851
0
                   << DumpHermesValue(runtime.thrownValue_) << "\n");
1852
0
        goto exception;
1853
0
      }
1854
1855
0
      CASE(ThrowIfEmpty) {
1856
0
        if (LLVM_UNLIKELY(O2REG(ThrowIfEmpty).isEmpty())) {
1857
0
          SLOW_DEBUG(dbgs() << "Throwing ReferenceError for empty variable");
1858
0
          CAPTURE_IP(runtime.raiseReferenceError(
1859
0
              "accessing an uninitialized variable"));
1860
0
          goto exception;
1861
0
        }
1862
0
        O1REG(ThrowIfEmpty) = O2REG(ThrowIfEmpty);
1863
0
        ip = NEXTINST(ThrowIfEmpty);
1864
0
        DISPATCH;
1865
0
      }
1866
1867
0
      CASE(Debugger) {
1868
0
        SLOW_DEBUG(dbgs() << "debugger statement executed\n");
1869
0
#ifdef HERMES_ENABLE_DEBUGGER
1870
0
        {
1871
0
          if (!runtime.debugger_.isDebugging()) {
1872
            // Only run the debugger if we're not already debugging.
1873
            // Don't want to call it again and mess with its state.
1874
0
            CAPTURE_IP_ASSIGN(
1875
0
                auto res,
1876
0
                runDebuggerUpdatingState(
1877
0
                    Debugger::RunReason::Opcode,
1878
0
                    runtime,
1879
0
                    curCodeBlock,
1880
0
                    ip,
1881
0
                    frameRegs));
1882
0
            if (res == ExecutionStatus::EXCEPTION) {
1883
              // If one of the internal steps threw,
1884
              // then handle that here by jumping to where we're supposed to go.
1885
              // If we're in mid-step, the breakpoint at the catch point
1886
              // will have been set by the debugger.
1887
              // We don't want to execute this instruction because it's already
1888
              // thrown.
1889
0
              goto exception;
1890
0
            }
1891
0
          }
1892
0
          InterpreterState newState{curCodeBlock, (uint32_t)CUROFFSET};
1893
0
          ExecutionStatus status =
1894
0
              runtime.debugger_.processInstUnderDebuggerOpCode(newState);
1895
0
          if (status == ExecutionStatus::EXCEPTION) {
1896
0
            goto exception;
1897
0
          }
1898
1899
0
          if (newState.codeBlock != curCodeBlock ||
1900
0
              newState.offset != (uint32_t)CUROFFSET) {
1901
0
            ip = newState.codeBlock->getOffsetPtr(newState.offset);
1902
1903
0
            if (newState.codeBlock != curCodeBlock) {
1904
0
              curCodeBlock = newState.codeBlock;
1905
0
              INIT_STATE_FOR_CODEBLOCK(curCodeBlock);
1906
              // Single-stepping should handle call stack management for us.
1907
0
              frameRegs = &runtime.getCurrentFrame().getFirstLocalRef();
1908
0
            }
1909
0
          }
1910
0
          gcScope.flushToSmallCount(KEEP_HANDLES);
1911
0
        }
1912
0
        DISPATCH;
1913
#else
1914
        ip = NEXTINST(Debugger);
1915
        DISPATCH;
1916
#endif
1917
0
      }
1918
1919
511k
      CASE(AsyncBreakCheck) {
1920
511k
        if (LLVM_UNLIKELY(runtime.hasAsyncBreak())) {
1921
0
#ifdef HERMES_ENABLE_DEBUGGER
1922
0
          if (uint8_t asyncFlags =
1923
0
                  runtime.testAndClearDebuggerAsyncBreakRequest()) {
1924
0
            RUN_DEBUGGER_ASYNC_BREAK(asyncFlags);
1925
0
          }
1926
0
#endif
1927
0
          if (runtime.testAndClearTimeoutAsyncBreakRequest()) {
1928
0
            CAPTURE_IP_ASSIGN(auto nRes, runtime.notifyTimeout());
1929
0
            if (nRes == ExecutionStatus::EXCEPTION) {
1930
0
              goto exception;
1931
0
            }
1932
0
          }
1933
0
        }
1934
511k
        gcScope.flushToSmallCount(KEEP_HANDLES);
1935
1936
511k
        ip = NEXTINST(AsyncBreakCheck);
1937
2.55M
        DISPATCH;
1938
2.55M
      }
1939
1940
0
      CASE(ProfilePoint) {
1941
#ifdef HERMESVM_PROFILER_BB
1942
        auto pointIndex = ip->iProfilePoint.op1;
1943
        SLOW_DEBUG(llvh::dbgs() << "ProfilePoint: " << pointIndex << "\n");
1944
        CAPTURE_IP(runtime.getBasicBlockExecutionInfo().executeBlock(
1945
            curCodeBlock, pointIndex));
1946
#endif
1947
0
        ip = NEXTINST(ProfilePoint);
1948
0
        DISPATCH;
1949
0
      }
1950
1951
      // Use a macro here to avoid clang-format issues with a literal default:
1952
      // label.
1953
0
      DEFAULT_CASE
1954
0
      CASE(Unreachable) {
1955
0
        hermes_fatal("Unreachable instruction encountered");
1956
        // The fatal call doesn't return, no need to set the IP differently and
1957
        // dispatch.
1958
0
      }
1959
1960
3.46k
      CASE(CreateClosure) {
1961
3.46k
        idVal = ip->iCreateClosure.op3;
1962
3.46k
        nextIP = NEXTINST(CreateClosure);
1963
3.46k
        goto createClosure;
1964
0
      }
1965
0
      CASE(CreateClosureLongIndex) {
1966
0
        idVal = ip->iCreateClosureLongIndex.op3;
1967
0
        nextIP = NEXTINST(CreateClosureLongIndex);
1968
0
        goto createClosure;
1969
0
      }
1970
3.46k
    createClosure: {
1971
3.46k
      auto *runtimeModule = curCodeBlock->getRuntimeModule();
1972
3.46k
      CAPTURE_IP(
1973
3.46k
          O1REG(CreateClosure) =
1974
3.46k
              JSFunction::create(
1975
3.46k
                  runtime,
1976
3.46k
                  runtimeModule->getDomain(runtime),
1977
3.46k
                  Handle<JSObject>::vmcast(&runtime.functionPrototype),
1978
3.46k
                  Handle<Environment>::vmcast(&O2REG(CreateClosure)),
1979
3.46k
                  runtimeModule->getCodeBlockMayAllocate(idVal))
1980
3.46k
                  .getHermesValue());
1981
3.46k
      gcScope.flushToSmallCount(KEEP_HANDLES);
1982
3.46k
      ip = nextIP;
1983
17.3k
      DISPATCH;
1984
17.3k
    }
1985
1986
0
      CASE(CreateAsyncClosure) {
1987
0
        idVal = ip->iCreateAsyncClosure.op3;
1988
0
        nextIP = NEXTINST(CreateAsyncClosure);
1989
0
        goto createAsyncClosure;
1990
17.3k
      }
1991
0
      CASE(CreateAsyncClosureLongIndex) {
1992
0
        idVal = ip->iCreateAsyncClosureLongIndex.op3;
1993
0
        nextIP = NEXTINST(CreateAsyncClosureLongIndex);
1994
0
        goto createAsyncClosure;
1995
17.3k
      }
1996
0
    createAsyncClosure: {
1997
0
      auto *runtimeModule = curCodeBlock->getRuntimeModule();
1998
0
      CAPTURE_IP_ASSIGN(
1999
0
          O1REG(CreateAsyncClosure),
2000
0
          JSAsyncFunction::create(
2001
0
              runtime,
2002
0
              runtimeModule->getDomain(runtime),
2003
0
              Handle<JSObject>::vmcast(&runtime.asyncFunctionPrototype),
2004
0
              Handle<Environment>::vmcast(&O2REG(CreateAsyncClosure)),
2005
0
              runtimeModule->getCodeBlockMayAllocate(idVal))
2006
0
              .getHermesValue());
2007
0
      gcScope.flushToSmallCount(KEEP_HANDLES);
2008
0
      ip = nextIP;
2009
0
      DISPATCH;
2010
0
    }
2011
2012
0
      CASE(CreateGeneratorClosure) {
2013
0
        idVal = ip->iCreateGeneratorClosure.op3;
2014
0
        nextIP = NEXTINST(CreateGeneratorClosure);
2015
0
        goto createGeneratorClosure;
2016
0
      }
2017
0
      CASE(CreateGeneratorClosureLongIndex) {
2018
0
        idVal = ip->iCreateGeneratorClosureLongIndex.op3;
2019
0
        nextIP = NEXTINST(CreateGeneratorClosureLongIndex);
2020
0
        goto createGeneratorClosure;
2021
0
      }
2022
0
    createGeneratorClosure: {
2023
0
      auto *runtimeModule = curCodeBlock->getRuntimeModule();
2024
0
      CAPTURE_IP_ASSIGN(
2025
0
          O1REG(CreateGeneratorClosure),
2026
0
          JSGeneratorFunction::create(
2027
0
              runtime,
2028
0
              runtimeModule->getDomain(runtime),
2029
0
              Handle<JSObject>::vmcast(&runtime.generatorFunctionPrototype),
2030
0
              Handle<Environment>::vmcast(&O2REG(CreateGeneratorClosure)),
2031
0
              runtimeModule->getCodeBlockMayAllocate(idVal))
2032
0
              .getHermesValue());
2033
0
      gcScope.flushToSmallCount(KEEP_HANDLES);
2034
0
      ip = nextIP;
2035
0
      DISPATCH;
2036
0
    }
2037
2038
0
      CASE(CreateGenerator) {
2039
0
        CAPTURE_IP_ASSIGN(
2040
0
            auto res,
2041
0
            createGenerator_RJS(
2042
0
                runtime,
2043
0
                curCodeBlock->getRuntimeModule(),
2044
0
                ip->iCreateGenerator.op3,
2045
0
                Handle<Environment>::vmcast(&O2REG(CreateGenerator)),
2046
0
                FRAME.getNativeArgs()));
2047
0
        if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
2048
0
          goto exception;
2049
0
        }
2050
0
        O1REG(CreateGenerator) = res->getHermesValue();
2051
0
        res->invalidate();
2052
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2053
0
        ip = NEXTINST(CreateGenerator);
2054
0
        DISPATCH;
2055
0
      }
2056
0
      CASE(CreateGeneratorLongIndex) {
2057
0
        CAPTURE_IP_ASSIGN(
2058
0
            auto res,
2059
0
            createGenerator_RJS(
2060
0
                runtime,
2061
0
                curCodeBlock->getRuntimeModule(),
2062
0
                ip->iCreateGeneratorLongIndex.op3,
2063
0
                Handle<Environment>::vmcast(&O2REG(CreateGeneratorLongIndex)),
2064
0
                FRAME.getNativeArgs()));
2065
0
        if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
2066
0
          goto exception;
2067
0
        }
2068
0
        O1REG(CreateGeneratorLongIndex) = res->getHermesValue();
2069
0
        res->invalidate();
2070
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2071
0
        ip = NEXTINST(CreateGeneratorLongIndex);
2072
0
        DISPATCH;
2073
0
      }
2074
2075
1.22k
      CASE(GetEnvironment) {
2076
        // The currently executing function must exist, so get the environment.
2077
1.22k
        Environment *curEnv =
2078
1.22k
            FRAME.getCalleeClosureUnsafe()->getEnvironment(runtime);
2079
1.22k
        for (unsigned level = ip->iGetEnvironment.op2; level; --level) {
2080
0
          assert(curEnv && "invalid environment relative level");
2081
0
          curEnv = curEnv->getParentEnvironment(runtime);
2082
0
        }
2083
1.22k
        O1REG(GetEnvironment) = HermesValue::encodeObjectValue(curEnv);
2084
1.22k
        ip = NEXTINST(GetEnvironment);
2085
6.11k
        DISPATCH;
2086
6.11k
      }
2087
2088
0
      CASE(CreateInnerEnvironment) {
2089
0
        CAPTURE_IP(
2090
0
            O1REG(CreateInnerEnvironment) = Environment::create(
2091
0
                runtime,
2092
0
                Handle<Environment>::vmcast(&O2REG(CreateInnerEnvironment)),
2093
0
                ip->iCreateInnerEnvironment.op3));
2094
0
        ip = NEXTINST(CreateInnerEnvironment);
2095
0
        DISPATCH;
2096
0
      }
2097
2098
513
      CASE(CreateEnvironment) {
2099
513
        tmpHandle = HermesValue::encodeObjectValueUnsafe(
2100
513
            FRAME.getCalleeClosureUnsafe()->getEnvironment(runtime));
2101
2102
513
        CAPTURE_IP(
2103
513
            O1REG(CreateEnvironment) = Environment::create(
2104
513
                runtime,
2105
513
                Handle<Environment>::vmcast_or_null(tmpHandle),
2106
513
                curCodeBlock->getEnvironmentSize()));
2107
2108
513
        tmpHandle = HermesValue::encodeUndefinedValue();
2109
513
        ip = NEXTINST(CreateEnvironment);
2110
2.56k
        DISPATCH;
2111
2.56k
      }
2112
2113
3.31k
      CASE(StoreToEnvironment) {
2114
3.31k
        vmcast<Environment>(O1REG(StoreToEnvironment))
2115
3.31k
            ->slot(ip->iStoreToEnvironment.op2)
2116
3.31k
            .set(O3REG(StoreToEnvironment), runtime.getHeap());
2117
3.31k
        ip = NEXTINST(StoreToEnvironment);
2118
16.5k
        DISPATCH;
2119
16.5k
      }
2120
0
      CASE(StoreToEnvironmentL) {
2121
0
        vmcast<Environment>(O1REG(StoreToEnvironmentL))
2122
0
            ->slot(ip->iStoreToEnvironmentL.op2)
2123
0
            .set(O3REG(StoreToEnvironmentL), runtime.getHeap());
2124
0
        ip = NEXTINST(StoreToEnvironmentL);
2125
0
        DISPATCH;
2126
0
      }
2127
2128
191
      CASE(StoreNPToEnvironment) {
2129
191
        vmcast<Environment>(O1REG(StoreNPToEnvironment))
2130
191
            ->slot(ip->iStoreNPToEnvironment.op2)
2131
191
            .setNonPtr(O3REG(StoreNPToEnvironment), runtime.getHeap());
2132
191
        ip = NEXTINST(StoreNPToEnvironment);
2133
955
        DISPATCH;
2134
955
      }
2135
0
      CASE(StoreNPToEnvironmentL) {
2136
0
        vmcast<Environment>(O1REG(StoreNPToEnvironmentL))
2137
0
            ->slot(ip->iStoreNPToEnvironmentL.op2)
2138
0
            .setNonPtr(O3REG(StoreNPToEnvironmentL), runtime.getHeap());
2139
0
        ip = NEXTINST(StoreNPToEnvironmentL);
2140
0
        DISPATCH;
2141
0
      }
2142
2143
1.22k
      CASE(LoadFromEnvironment) {
2144
1.22k
        O1REG(LoadFromEnvironment) =
2145
1.22k
            vmcast<Environment>(O2REG(LoadFromEnvironment))
2146
1.22k
                ->slot(ip->iLoadFromEnvironment.op3);
2147
1.22k
        ip = NEXTINST(LoadFromEnvironment);
2148
6.11k
        DISPATCH;
2149
6.11k
      }
2150
2151
0
      CASE(LoadFromEnvironmentL) {
2152
0
        O1REG(LoadFromEnvironmentL) =
2153
0
            vmcast<Environment>(O2REG(LoadFromEnvironmentL))
2154
0
                ->slot(ip->iLoadFromEnvironmentL.op3);
2155
0
        ip = NEXTINST(LoadFromEnvironmentL);
2156
0
        DISPATCH;
2157
0
      }
2158
2159
512k
      CASE(GetGlobalObject) {
2160
512k
        O1REG(GetGlobalObject) = runtime.global_;
2161
512k
        ip = NEXTINST(GetGlobalObject);
2162
2.56M
        DISPATCH;
2163
2.56M
      }
2164
2165
9
      CASE(GetNewTarget) {
2166
9
        O1REG(GetNewTarget) = FRAME.getNewTargetRef();
2167
9
        ip = NEXTINST(GetNewTarget);
2168
45
        DISPATCH;
2169
45
      }
2170
2171
0
      CASE(DeclareGlobalVar) {
2172
0
        CAPTURE_IP_ASSIGN(
2173
0
            auto res, declareGlobalVarImpl(runtime, curCodeBlock, ip));
2174
0
        if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
2175
0
          goto exception;
2176
0
        }
2177
0
        ip = NEXTINST(DeclareGlobalVar);
2178
0
        DISPATCH;
2179
0
      }
2180
2181
0
      CASE(ThrowIfHasRestrictedGlobalProperty) {
2182
0
        CAPTURE_IP_ASSIGN(
2183
0
            auto res,
2184
0
            throwIfHasRestrictedGlobalPropertyImpl(runtime, curCodeBlock, ip));
2185
0
        if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
2186
0
          goto exception;
2187
0
        }
2188
0
        ip = NEXTINST(ThrowIfHasRestrictedGlobalProperty);
2189
0
        DISPATCH;
2190
0
      }
2191
2192
0
      CASE(TryGetByIdLong) {
2193
0
        tryProp = true;
2194
0
        idVal = ip->iTryGetByIdLong.op4;
2195
0
        nextIP = NEXTINST(TryGetByIdLong);
2196
0
        goto getById;
2197
0
      }
2198
0
      CASE(GetByIdLong) {
2199
0
        tryProp = false;
2200
0
        idVal = ip->iGetByIdLong.op4;
2201
0
        nextIP = NEXTINST(GetByIdLong);
2202
0
        goto getById;
2203
0
      }
2204
2.25k
      CASE(GetByIdShort) {
2205
2.25k
        tryProp = false;
2206
2.25k
        idVal = ip->iGetByIdShort.op4;
2207
2.25k
        nextIP = NEXTINST(GetByIdShort);
2208
2.25k
        goto getById;
2209
0
      }
2210
1.05k
      CASE(TryGetById) {
2211
1.05k
        tryProp = true;
2212
1.05k
        idVal = ip->iTryGetById.op4;
2213
1.05k
        nextIP = NEXTINST(TryGetById);
2214
1.05k
        goto getById;
2215
0
      }
2216
0
      CASE(GetById) {
2217
0
        tryProp = false;
2218
0
        idVal = ip->iGetById.op4;
2219
0
        nextIP = NEXTINST(GetById);
2220
0
      }
2221
3.31k
    getById: {
2222
3.31k
      ++NumGetById;
2223
      // NOTE: it is safe to use OnREG(GetById) here because all instructions
2224
      // have the same layout: opcode, registers, non-register operands, i.e.
2225
      // they only differ in the width of the last "identifier" field.
2226
3.31k
      if (LLVM_LIKELY(O2REG(GetById).isObject())) {
2227
3.31k
        auto *obj = vmcast<JSObject>(O2REG(GetById));
2228
3.31k
        auto cacheIdx = ip->iGetById.op3;
2229
3.31k
        auto *cacheEntry = curCodeBlock->getReadCacheEntry(cacheIdx);
2230
2231
#ifdef HERMESVM_PROFILER_BB
2232
        {
2233
          HERMES_SLOW_ASSERT(
2234
              gcScope.getHandleCountDbg() == KEEP_HANDLES &&
2235
              "unaccounted handles were created");
2236
          auto objHandle = runtime.makeHandle(obj);
2237
          auto cacheHCPtr = vmcast_or_null<HiddenClass>(static_cast<GCCell *>(
2238
              cacheEntry->clazz.get(runtime, runtime.getHeap())));
2239
          CAPTURE_IP(runtime.recordHiddenClass(
2240
              curCodeBlock, ip, ID(idVal), obj->getClass(runtime), cacheHCPtr));
2241
          // obj may be moved by GC due to recordHiddenClass
2242
          obj = objHandle.get();
2243
        }
2244
        gcScope.flushToSmallCount(KEEP_HANDLES);
2245
#endif
2246
3.31k
        CompressedPointer clazzPtr{obj->getClassGCPtr()};
2247
3.31k
#ifndef NDEBUG
2248
3.31k
        if (vmcast<HiddenClass>(clazzPtr.getNonNull(runtime))->isDictionary())
2249
119
          ++NumGetByIdDict;
2250
#else
2251
        (void)NumGetByIdDict;
2252
#endif
2253
2254
        // If we have a cache hit, reuse the cached offset and immediately
2255
        // return the property.
2256
3.31k
        if (LLVM_LIKELY(cacheEntry->clazz == clazzPtr)) {
2257
1.20k
          ++NumGetByIdCacheHits;
2258
1.20k
          CAPTURE_IP(
2259
1.20k
              O1REG(GetById) =
2260
1.20k
                  JSObject::getNamedSlotValueUnsafe<PropStorage::Inline::Yes>(
2261
1.20k
                      obj, runtime, cacheEntry->slot)
2262
1.20k
                      .unboxToHV(runtime));
2263
1.20k
          ip = nextIP;
2264
6.02k
          DISPATCH;
2265
6.02k
        }
2266
3.31k
        auto id = ID(idVal);
2267
3.31k
        NamedPropertyDescriptor desc;
2268
3.31k
        CAPTURE_IP_ASSIGN(
2269
3.31k
            OptValue<bool> fastPathResult,
2270
3.31k
            JSObject::tryGetOwnNamedDescriptorFast(obj, runtime, id, desc));
2271
3.31k
        if (LLVM_LIKELY(
2272
3.31k
                fastPathResult.hasValue() && fastPathResult.getValue()) &&
2273
1.89k
            !desc.flags.accessor) {
2274
1.89k
          ++NumGetByIdFastPaths;
2275
2276
          // cacheIdx == 0 indicates no caching so don't update the cache in
2277
          // those cases.
2278
1.89k
          HiddenClass *clazz =
2279
1.89k
              vmcast<HiddenClass>(clazzPtr.getNonNull(runtime));
2280
1.89k
          if (LLVM_LIKELY(!clazz->isDictionaryNoCache()) &&
2281
1.89k
              LLVM_LIKELY(cacheIdx != hbc::PROPERTY_CACHING_DISABLED)) {
2282
1.89k
#ifdef HERMES_SLOW_DEBUG
2283
1.89k
            if (cacheEntry->clazz && cacheEntry->clazz != clazzPtr)
2284
376
              ++NumGetByIdCacheEvicts;
2285
#else
2286
            (void)NumGetByIdCacheEvicts;
2287
#endif
2288
            // Cache the class, id and property slot.
2289
1.89k
            cacheEntry->clazz = clazzPtr;
2290
1.89k
            cacheEntry->slot = desc.slot;
2291
1.89k
          }
2292
2293
1.89k
          assert(
2294
1.89k
              !obj->isProxyObject() &&
2295
1.89k
              "tryGetOwnNamedDescriptorFast returned true on Proxy");
2296
1.89k
          CAPTURE_IP(
2297
1.89k
              O1REG(GetById) =
2298
1.89k
                  JSObject::getNamedSlotValueUnsafe(obj, runtime, desc)
2299
1.89k
                      .unboxToHV(runtime));
2300
1.89k
          ip = nextIP;
2301
9.48k
          DISPATCH;
2302
9.48k
        }
2303
2304
        // The cache may also be populated via the prototype of the object.
2305
        // This value is only reliable if the fast path was a definite
2306
        // not-found.
2307
3.31k
        if (fastPathResult.hasValue() && !fastPathResult.getValue() &&
2308
27
            LLVM_LIKELY(!obj->isProxyObject())) {
2309
27
          CAPTURE_IP_ASSIGN(JSObject * parent, obj->getParent(runtime));
2310
          // TODO: This isLazy check is because a lazy object is reported as
2311
          // having no properties and therefore cannot contain the property.
2312
          // This check does not belong here, it should be merged into
2313
          // tryGetOwnNamedDescriptorFast().
2314
27
          if (parent && cacheEntry->clazz == parent->getClassGCPtr() &&
2315
0
              LLVM_LIKELY(!obj->isLazy())) {
2316
0
            ++NumGetByIdProtoHits;
2317
            // We've already checked that this isn't a Proxy.
2318
0
            CAPTURE_IP(
2319
0
                O1REG(GetById) = JSObject::getNamedSlotValueUnsafe(
2320
0
                                     parent, runtime, cacheEntry->slot)
2321
0
                                     .unboxToHV(runtime));
2322
0
            ip = nextIP;
2323
0
            DISPATCH;
2324
0
          }
2325
27
        }
2326
2327
3.31k
#ifdef HERMES_SLOW_DEBUG
2328
        // Call to getNamedDescriptorUnsafe is safe because `id` is kept alive
2329
        // by the IdentifierTable.
2330
3.31k
        CAPTURE_IP_ASSIGN(
2331
3.31k
            JSObject * propObj,
2332
3.31k
            JSObject::getNamedDescriptorUnsafe(
2333
3.31k
                Handle<JSObject>::vmcast(&O2REG(GetById)), runtime, id, desc));
2334
3.31k
        if (propObj) {
2335
188
          if (desc.flags.accessor)
2336
0
            ++NumGetByIdAccessor;
2337
188
          else if (propObj != vmcast<JSObject>(O2REG(GetById)))
2338
94
            ++NumGetByIdProto;
2339
3.12k
        } else {
2340
3.12k
          ++NumGetByIdNotFound;
2341
3.12k
        }
2342
#else
2343
        (void)NumGetByIdAccessor;
2344
        (void)NumGetByIdProto;
2345
        (void)NumGetByIdNotFound;
2346
#endif
2347
3.31k
#ifdef HERMES_SLOW_DEBUG
2348
3.31k
        auto *savedClass = cacheIdx != hbc::PROPERTY_CACHING_DISABLED
2349
3.31k
            ? cacheEntry->clazz.get(runtime, runtime.getHeap())
2350
3.31k
            : nullptr;
2351
3.31k
#endif
2352
3.31k
        ++NumGetByIdSlow;
2353
3.31k
        CAPTURE_IP(
2354
3.31k
            resPH = JSObject::getNamed_RJS(
2355
3.31k
                Handle<JSObject>::vmcast(&O2REG(GetById)),
2356
3.31k
                runtime,
2357
3.31k
                id,
2358
3.31k
                !tryProp ? defaultPropOpFlags
2359
3.31k
                         : defaultPropOpFlags.plusMustExist(),
2360
3.31k
                cacheIdx != hbc::PROPERTY_CACHING_DISABLED ? cacheEntry
2361
3.31k
                                                           : nullptr));
2362
3.31k
        if (LLVM_UNLIKELY(resPH == ExecutionStatus::EXCEPTION)) {
2363
25
          goto exception;
2364
25
        }
2365
3.29k
#ifdef HERMES_SLOW_DEBUG
2366
3.29k
        if (cacheIdx != hbc::PROPERTY_CACHING_DISABLED && savedClass &&
2367
0
            cacheEntry->clazz.get(runtime, runtime.getHeap()) != savedClass) {
2368
0
          ++NumGetByIdCacheEvicts;
2369
0
        }
2370
3.29k
#endif
2371
3.29k
      } else {
2372
0
        ++NumGetByIdTransient;
2373
0
        assert(!tryProp && "TryGetById can only be used on the global object");
2374
        /* Slow path. */
2375
0
        CAPTURE_IP(
2376
0
            resPH = Interpreter::getByIdTransient_RJS(
2377
0
                runtime, Handle<>(&O2REG(GetById)), ID(idVal)));
2378
0
        if (LLVM_UNLIKELY(resPH == ExecutionStatus::EXCEPTION)) {
2379
0
          goto exception;
2380
0
        }
2381
0
      }
2382
3.29k
      O1REG(GetById) = resPH->get();
2383
3.29k
      gcScope.flushToSmallCount(KEEP_HANDLES);
2384
3.29k
      ip = nextIP;
2385
3.29k
      DISPATCH;
2386
950
    }
2387
2388
0
      CASE(TryPutByIdLong) {
2389
0
        tryProp = true;
2390
0
        idVal = ip->iTryPutByIdLong.op4;
2391
0
        nextIP = NEXTINST(TryPutByIdLong);
2392
0
        goto putById;
2393
950
      }
2394
0
      CASE(PutByIdLong) {
2395
0
        tryProp = false;
2396
0
        idVal = ip->iPutByIdLong.op4;
2397
0
        nextIP = NEXTINST(PutByIdLong);
2398
0
        goto putById;
2399
950
      }
2400
0
      CASE(TryPutById) {
2401
0
        tryProp = true;
2402
0
        idVal = ip->iTryPutById.op4;
2403
0
        nextIP = NEXTINST(TryPutById);
2404
0
        goto putById;
2405
950
      }
2406
516k
      CASE(PutById) {
2407
516k
        tryProp = false;
2408
516k
        idVal = ip->iPutById.op4;
2409
516k
        nextIP = NEXTINST(PutById);
2410
516k
      }
2411
516k
    putById: {
2412
516k
      ++NumPutById;
2413
516k
      if (LLVM_LIKELY(O1REG(PutById).isObject())) {
2414
516k
        CAPTURE_IP_ASSIGN(
2415
516k
            SmallHermesValue shv,
2416
516k
            SmallHermesValue::encodeHermesValue(O2REG(PutById), runtime));
2417
516k
        auto *obj = vmcast<JSObject>(O1REG(PutById));
2418
516k
        auto cacheIdx = ip->iPutById.op3;
2419
516k
        auto *cacheEntry = curCodeBlock->getWriteCacheEntry(cacheIdx);
2420
2421
#ifdef HERMESVM_PROFILER_BB
2422
        {
2423
          HERMES_SLOW_ASSERT(
2424
              gcScope.getHandleCountDbg() == KEEP_HANDLES &&
2425
              "unaccounted handles were created");
2426
          auto shvHandle = runtime.makeHandle(shv.toHV(runtime));
2427
          auto objHandle = runtime.makeHandle(obj);
2428
          auto cacheHCPtr = vmcast_or_null<HiddenClass>(static_cast<GCCell *>(
2429
              cacheEntry->clazz.get(runtime, runtime.getHeap())));
2430
          CAPTURE_IP(runtime.recordHiddenClass(
2431
              curCodeBlock, ip, ID(idVal), obj->getClass(runtime), cacheHCPtr));
2432
          // shv/obj may be invalidated by recordHiddenClass
2433
          if (shv.isPointer())
2434
            shv.unsafeUpdatePointer(
2435
                static_cast<GCCell *>(shvHandle->getPointer()), runtime);
2436
          obj = objHandle.get();
2437
        }
2438
        gcScope.flushToSmallCount(KEEP_HANDLES);
2439
#endif
2440
516k
        CompressedPointer clazzPtr{obj->getClassGCPtr()};
2441
        // If we have a cache hit, reuse the cached offset and immediately
2442
        // return the property.
2443
516k
        if (LLVM_LIKELY(cacheEntry->clazz == clazzPtr)) {
2444
940
          ++NumPutByIdCacheHits;
2445
940
          CAPTURE_IP(
2446
940
              JSObject::setNamedSlotValueUnsafe<PropStorage::Inline::Yes>(
2447
940
                  obj, runtime, cacheEntry->slot, shv));
2448
940
          ip = nextIP;
2449
4.70k
          DISPATCH;
2450
4.70k
        }
2451
516k
        auto id = ID(idVal);
2452
516k
        NamedPropertyDescriptor desc;
2453
516k
        CAPTURE_IP_ASSIGN(
2454
516k
            OptValue<bool> hasOwnProp,
2455
516k
            JSObject::tryGetOwnNamedDescriptorFast(obj, runtime, id, desc));
2456
516k
        if (LLVM_LIKELY(hasOwnProp.hasValue() && hasOwnProp.getValue()) &&
2457
511k
            !desc.flags.accessor && desc.flags.writable &&
2458
511k
            !desc.flags.internalSetter) {
2459
511k
          ++NumPutByIdFastPaths;
2460
2461
          // cacheIdx == 0 indicates no caching so don't update the cache in
2462
          // those cases.
2463
511k
          HiddenClass *clazz =
2464
511k
              vmcast<HiddenClass>(clazzPtr.getNonNull(runtime));
2465
511k
          if (LLVM_LIKELY(!clazz->isDictionary()) &&
2466
188
              LLVM_LIKELY(cacheIdx != hbc::PROPERTY_CACHING_DISABLED)) {
2467
188
#ifdef HERMES_SLOW_DEBUG
2468
188
            if (cacheEntry->clazz && cacheEntry->clazz != clazzPtr)
2469
0
              ++NumPutByIdCacheEvicts;
2470
#else
2471
            (void)NumPutByIdCacheEvicts;
2472
#endif
2473
            // Cache the class and property slot.
2474
188
            cacheEntry->clazz = clazzPtr;
2475
188
            cacheEntry->slot = desc.slot;
2476
188
          }
2477
2478
          // This must be valid because an own property was already found.
2479
511k
          CAPTURE_IP(
2480
511k
              JSObject::setNamedSlotValueUnsafe(obj, runtime, desc.slot, shv));
2481
511k
          ip = nextIP;
2482
2.55M
          DISPATCH;
2483
2.55M
        }
2484
2485
516k
        CAPTURE_IP_ASSIGN(
2486
516k
            auto putRes,
2487
516k
            JSObject::putNamed_RJS(
2488
516k
                Handle<JSObject>::vmcast(&O1REG(PutById)),
2489
516k
                runtime,
2490
516k
                id,
2491
516k
                Handle<>(&O2REG(PutById)),
2492
516k
                !tryProp ? defaultPropOpFlags
2493
516k
                         : defaultPropOpFlags.plusMustExist()));
2494
516k
        if (LLVM_UNLIKELY(putRes == ExecutionStatus::EXCEPTION)) {
2495
0
          goto exception;
2496
0
        }
2497
516k
      } else {
2498
0
        ++NumPutByIdTransient;
2499
0
        assert(!tryProp && "TryPutById can only be used on the global object");
2500
0
        CAPTURE_IP_ASSIGN(
2501
0
            auto retStatus,
2502
0
            Interpreter::putByIdTransient_RJS(
2503
0
                runtime,
2504
0
                Handle<>(&O1REG(PutById)),
2505
0
                ID(idVal),
2506
0
                Handle<>(&O2REG(PutById)),
2507
0
                strictMode));
2508
0
        if (retStatus == ExecutionStatus::EXCEPTION) {
2509
0
          goto exception;
2510
0
        }
2511
0
      }
2512
516k
      gcScope.flushToSmallCount(KEEP_HANDLES);
2513
516k
      ip = nextIP;
2514
516k
      DISPATCH;
2515
17.9k
    }
2516
2517
0
      CASE(GetByVal) {
2518
0
        if (LLVM_LIKELY(O2REG(GetByVal).isObject())) {
2519
0
          CAPTURE_IP(
2520
0
              resPH = JSObject::getComputed_RJS(
2521
0
                  Handle<JSObject>::vmcast(&O2REG(GetByVal)),
2522
0
                  runtime,
2523
0
                  Handle<>(&O3REG(GetByVal))));
2524
0
          if (LLVM_UNLIKELY(resPH == ExecutionStatus::EXCEPTION)) {
2525
0
            goto exception;
2526
0
          }
2527
0
        } else {
2528
          // This is the "slow path".
2529
0
          CAPTURE_IP(
2530
0
              resPH = Interpreter::getByValTransient_RJS(
2531
0
                  runtime,
2532
0
                  Handle<>(&O2REG(GetByVal)),
2533
0
                  Handle<>(&O3REG(GetByVal))));
2534
0
          if (LLVM_UNLIKELY(resPH == ExecutionStatus::EXCEPTION)) {
2535
0
            goto exception;
2536
0
          }
2537
0
        }
2538
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2539
0
        O1REG(GetByVal) = resPH->get();
2540
0
        ip = NEXTINST(GetByVal);
2541
0
        DISPATCH;
2542
0
      }
2543
2544
0
      CASE(PutByVal) {
2545
0
        if (LLVM_LIKELY(O1REG(PutByVal).isObject())) {
2546
0
          CAPTURE_IP_ASSIGN(
2547
0
              auto putRes,
2548
0
              JSObject::putComputed_RJS(
2549
0
                  Handle<JSObject>::vmcast(&O1REG(PutByVal)),
2550
0
                  runtime,
2551
0
                  Handle<>(&O2REG(PutByVal)),
2552
0
                  Handle<>(&O3REG(PutByVal)),
2553
0
                  defaultPropOpFlags));
2554
0
          if (LLVM_UNLIKELY(putRes == ExecutionStatus::EXCEPTION)) {
2555
0
            goto exception;
2556
0
          }
2557
0
        } else {
2558
          // This is the "slow path".
2559
0
          CAPTURE_IP_ASSIGN(
2560
0
              auto retStatus,
2561
0
              Interpreter::putByValTransient_RJS(
2562
0
                  runtime,
2563
0
                  Handle<>(&O1REG(PutByVal)),
2564
0
                  Handle<>(&O2REG(PutByVal)),
2565
0
                  Handle<>(&O3REG(PutByVal)),
2566
0
                  strictMode));
2567
0
          if (LLVM_UNLIKELY(retStatus == ExecutionStatus::EXCEPTION)) {
2568
0
            goto exception;
2569
0
          }
2570
0
        }
2571
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2572
0
        ip = NEXTINST(PutByVal);
2573
0
        DISPATCH;
2574
0
      }
2575
2576
424k
      CASE(PutOwnByIndexL) {
2577
424k
        nextIP = NEXTINST(PutOwnByIndexL);
2578
424k
        idVal = ip->iPutOwnByIndexL.op3;
2579
424k
        goto putOwnByIndex;
2580
0
      }
2581
282
      CASE(PutOwnByIndex) {
2582
282
        nextIP = NEXTINST(PutOwnByIndex);
2583
282
        idVal = ip->iPutOwnByIndex.op3;
2584
282
      }
2585
425k
    putOwnByIndex: {
2586
425k
      tmpHandle = HermesValue::encodeUntrustedNumberValue(idVal);
2587
425k
      CAPTURE_IP(
2588
425k
          JSObject::defineOwnComputedPrimitive(
2589
425k
              Handle<JSObject>::vmcast(&O1REG(PutOwnByIndex)),
2590
425k
              runtime,
2591
425k
              tmpHandle,
2592
425k
              DefinePropertyFlags::getDefaultNewPropertyFlags(),
2593
425k
              Handle<>(&O2REG(PutOwnByIndex))));
2594
425k
      gcScope.flushToSmallCount(KEEP_HANDLES);
2595
425k
      tmpHandle.clear();
2596
425k
      ip = nextIP;
2597
2.12M
      DISPATCH;
2598
2.12M
    }
2599
2600
425k
      CASE_OUTOFLINE(GetPNameList);
2601
2602
511k
      CASE(GetNextPName) {
2603
511k
        {
2604
511k
          assert(
2605
511k
              vmisa<BigStorage>(O2REG(GetNextPName)) &&
2606
511k
              "GetNextPName's second op must be BigStorage");
2607
511k
          auto obj = Handle<JSObject>::vmcast(&O3REG(GetNextPName));
2608
511k
          auto arr = Handle<BigStorage>::vmcast(&O2REG(GetNextPName));
2609
511k
          uint32_t idx = O4REG(GetNextPName).getNumber();
2610
511k
          uint32_t size = O5REG(GetNextPName).getNumber();
2611
511k
          MutableHandle<JSObject> propObj{runtime};
2612
511k
          MutableHandle<SymbolID> tmpPropNameStorage{runtime};
2613
          // Loop until we find a property which is present.
2614
511k
          while (idx < size) {
2615
511k
            tmpHandle = arr->at(runtime, idx);
2616
511k
            ComputedPropertyDescriptor desc;
2617
511k
            CAPTURE_IP_ASSIGN(
2618
511k
                ExecutionStatus status,
2619
511k
                JSObject::getComputedPrimitiveDescriptor(
2620
511k
                    obj,
2621
511k
                    runtime,
2622
511k
                    tmpHandle,
2623
511k
                    propObj,
2624
511k
                    tmpPropNameStorage,
2625
511k
                    desc));
2626
511k
            if (LLVM_UNLIKELY(status == ExecutionStatus::EXCEPTION)) {
2627
0
              goto exception;
2628
0
            }
2629
511k
            if (LLVM_LIKELY(propObj))
2630
511k
              break;
2631
0
            ++idx;
2632
0
          }
2633
511k
          if (idx < size) {
2634
            // We must return the property as a string
2635
511k
            if (tmpHandle->isNumber()) {
2636
511k
              CAPTURE_IP_ASSIGN(auto status, toString_RJS(runtime, tmpHandle));
2637
511k
              assert(
2638
511k
                  status == ExecutionStatus::RETURNED &&
2639
511k
                  "toString on number cannot fail");
2640
511k
              tmpHandle = status->getHermesValue();
2641
511k
            }
2642
511k
            O4REG(GetNextPName) =
2643
511k
                HermesValue::encodeUntrustedNumberValue(idx + 1);
2644
            // Write the result last in case it is the same register as O4REG.
2645
511k
            O1REG(GetNextPName) = tmpHandle.get();
2646
511k
          } else {
2647
5
            O1REG(GetNextPName) = HermesValue::encodeUndefinedValue();
2648
5
          }
2649
511k
        }
2650
511k
        gcScope.flushToSmallCount(KEEP_HANDLES);
2651
511k
        tmpHandle.clear();
2652
511k
        ip = NEXTINST(GetNextPName);
2653
2.55M
        DISPATCH;
2654
2.55M
      }
2655
2656
6
      CASE(ToNumber) {
2657
6
        if (LLVM_LIKELY(O2REG(ToNumber).isNumber())) {
2658
0
          O1REG(ToNumber) = O2REG(ToNumber);
2659
0
          ip = NEXTINST(ToNumber);
2660
6
        } else {
2661
6
          CAPTURE_IP(res = toNumber_RJS(runtime, Handle<>(&O2REG(ToNumber))));
2662
6
          if (res == ExecutionStatus::EXCEPTION)
2663
0
            goto exception;
2664
6
          gcScope.flushToSmallCount(KEEP_HANDLES);
2665
6
          O1REG(ToNumber) = res.getValue();
2666
6
          ip = NEXTINST(ToNumber);
2667
6
        }
2668
36
        DISPATCH;
2669
36
      }
2670
2671
0
      CASE(ToNumeric) {
2672
0
        if (LLVM_LIKELY(O2REG(ToNumeric).isNumber())) {
2673
0
          O1REG(ToNumeric) = O2REG(ToNumeric);
2674
0
          ip = NEXTINST(ToNumeric);
2675
0
        } else {
2676
0
          CAPTURE_IP(res = toNumeric_RJS(runtime, Handle<>(&O2REG(ToNumeric))));
2677
0
          if (res == ExecutionStatus::EXCEPTION)
2678
0
            goto exception;
2679
0
          gcScope.flushToSmallCount(KEEP_HANDLES);
2680
0
          O1REG(ToNumeric) = res.getValue();
2681
0
          ip = NEXTINST(ToNumeric);
2682
0
        }
2683
0
        DISPATCH;
2684
0
      }
2685
2686
0
      CASE(ToInt32) {
2687
0
        CAPTURE_IP(res = toInt32_RJS(runtime, Handle<>(&O2REG(ToInt32))));
2688
0
        if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION))
2689
0
          goto exception;
2690
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2691
0
        O1REG(ToInt32) = res.getValue();
2692
0
        ip = NEXTINST(ToInt32);
2693
0
        DISPATCH;
2694
0
      }
2695
2696
0
      CASE(AddEmptyString) {
2697
0
        if (LLVM_LIKELY(O2REG(AddEmptyString).isString())) {
2698
0
          O1REG(AddEmptyString) = O2REG(AddEmptyString);
2699
0
          ip = NEXTINST(AddEmptyString);
2700
0
        } else {
2701
0
          CAPTURE_IP(
2702
0
              res = toPrimitive_RJS(
2703
0
                  runtime,
2704
0
                  Handle<>(&O2REG(AddEmptyString)),
2705
0
                  PreferredType::NONE));
2706
0
          if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION))
2707
0
            goto exception;
2708
0
          tmpHandle = res.getValue();
2709
0
          CAPTURE_IP_ASSIGN(auto strRes, toString_RJS(runtime, tmpHandle));
2710
0
          if (LLVM_UNLIKELY(strRes == ExecutionStatus::EXCEPTION))
2711
0
            goto exception;
2712
0
          tmpHandle.clear();
2713
0
          gcScope.flushToSmallCount(KEEP_HANDLES);
2714
0
          O1REG(AddEmptyString) = strRes->getHermesValue();
2715
0
          ip = NEXTINST(AddEmptyString);
2716
0
        }
2717
0
        DISPATCH;
2718
0
      }
2719
2720
511k
      CASE(Jmp) {
2721
511k
        ip = IPADD(ip->iJmp.op1);
2722
2.55M
        DISPATCH;
2723
2.55M
      }
2724
0
      CASE(JmpLong) {
2725
0
        ip = IPADD(ip->iJmpLong.op1);
2726
0
        DISPATCH;
2727
0
      }
2728
665
      CASE(JmpTrue) {
2729
665
        if (toBoolean(O2REG(JmpTrue)))
2730
100
          ip = IPADD(ip->iJmpTrue.op1);
2731
565
        else
2732
565
          ip = NEXTINST(JmpTrue);
2733
3.32k
        DISPATCH;
2734
3.32k
      }
2735
7
      CASE(JmpTrueLong) {
2736
7
        if (toBoolean(O2REG(JmpTrueLong)))
2737
7
          ip = IPADD(ip->iJmpTrueLong.op1);
2738
0
        else
2739
0
          ip = NEXTINST(JmpTrueLong);
2740
35
        DISPATCH;
2741
35
      }
2742
188
      CASE(JmpFalse) {
2743
188
        if (!toBoolean(O2REG(JmpFalse)))
2744
94
          ip = IPADD(ip->iJmpFalse.op1);
2745
94
        else
2746
94
          ip = NEXTINST(JmpFalse);
2747
940
        DISPATCH;
2748
940
      }
2749
0
      CASE(JmpFalseLong) {
2750
0
        if (!toBoolean(O2REG(JmpFalseLong)))
2751
0
          ip = IPADD(ip->iJmpFalseLong.op1);
2752
0
        else
2753
0
          ip = NEXTINST(JmpFalseLong);
2754
0
        DISPATCH;
2755
0
      }
2756
511k
      CASE(JmpUndefined) {
2757
511k
        if (O2REG(JmpUndefined).isUndefined())
2758
5
          ip = IPADD(ip->iJmpUndefined.op1);
2759
511k
        else
2760
511k
          ip = NEXTINST(JmpUndefined);
2761
2.55M
        DISPATCH;
2762
2.55M
      }
2763
0
      CASE(JmpUndefinedLong) {
2764
0
        if (O2REG(JmpUndefinedLong).isUndefined())
2765
0
          ip = IPADD(ip->iJmpUndefinedLong.op1);
2766
0
        else
2767
0
          ip = NEXTINST(JmpUndefinedLong);
2768
0
        DISPATCH;
2769
0
      }
2770
0
      INCDECOP(Inc)
2771
0
      INCDECOP(Dec)
2772
1.15k
      CASE(Add) {
2773
1.15k
        if (LLVM_LIKELY(
2774
1.15k
                O2REG(Add).isNumber() &&
2775
1.15k
                O3REG(Add).isNumber())) { /* Fast-path. */
2776
5
          INTERPRETER_FALLTHROUGH;
2777
5
          CASE(AddN) {
2778
5
            O1REG(Add) = HermesValue::encodeTrustedNumberValue(
2779
5
                O2REG(Add).getNumber() + O3REG(Add).getNumber());
2780
5
            ip = NEXTINST(Add);
2781
25
            DISPATCH;
2782
25
          }
2783
25
        }
2784
1.15k
        CAPTURE_IP(
2785
1.15k
            res = addOp_RJS(
2786
1.15k
                runtime, Handle<>(&O2REG(Add)), Handle<>(&O3REG(Add))));
2787
1.15k
        if (res == ExecutionStatus::EXCEPTION) {
2788
0
          goto exception;
2789
0
        }
2790
1.15k
        gcScope.flushToSmallCount(KEEP_HANDLES);
2791
1.15k
        O1REG(Add) = res.getValue();
2792
1.15k
        ip = NEXTINST(Add);
2793
5.72k
        DISPATCH;
2794
5.72k
      }
2795
2796
0
      CASE(BitNot) {
2797
0
        if (LLVM_LIKELY(O2REG(BitNot).isNumber())) { /* Fast-path. */
2798
0
          O1REG(BitNot) = HermesValue::encodeUntrustedNumberValue(
2799
0
              ~hermes::truncateToInt32(O2REG(BitNot).getNumber()));
2800
0
          ip = NEXTINST(BitNot);
2801
0
          DISPATCH;
2802
0
        }
2803
0
        CAPTURE_IP(res = doBitNotSlowPath(runtime, Handle<>(&O2REG(BitNot))));
2804
0
        if (res == ExecutionStatus::EXCEPTION) {
2805
0
          goto exception;
2806
0
        }
2807
0
        O1REG(BitNot) = *res;
2808
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2809
0
        ip = NEXTINST(BitNot);
2810
0
        DISPATCH;
2811
0
      }
2812
2813
0
      CASE(GetArgumentsLength) {
2814
        // If the arguments object hasn't been created yet.
2815
0
        if (O2REG(GetArgumentsLength).isUndefined()) {
2816
0
          O1REG(GetArgumentsLength) =
2817
0
              HermesValue::encodeUntrustedNumberValue(FRAME.getArgCount());
2818
0
          ip = NEXTINST(GetArgumentsLength);
2819
0
          DISPATCH;
2820
0
        }
2821
        // The arguments object has been created, so this is a regular property
2822
        // get.
2823
0
        assert(
2824
0
            O2REG(GetArgumentsLength).isObject() &&
2825
0
            "arguments lazy register is not an object");
2826
0
        CAPTURE_IP(
2827
0
            resPH = JSObject::getNamed_RJS(
2828
0
                Handle<JSObject>::vmcast(&O2REG(GetArgumentsLength)),
2829
0
                runtime,
2830
0
                Predefined::getSymbolID(Predefined::length)));
2831
0
        if (resPH == ExecutionStatus::EXCEPTION) {
2832
0
          goto exception;
2833
0
        }
2834
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2835
0
        O1REG(GetArgumentsLength) = resPH->get();
2836
0
        ip = NEXTINST(GetArgumentsLength);
2837
0
        DISPATCH;
2838
0
      }
2839
2840
0
      CASE(GetArgumentsPropByVal) {
2841
        // If the arguments object hasn't been created yet and we have a
2842
        // valid integer index, we use the fast path.
2843
0
        if (O3REG(GetArgumentsPropByVal).isUndefined()) {
2844
          // If this is an integer index.
2845
0
          if (auto index = toArrayIndexFastPath(O2REG(GetArgumentsPropByVal))) {
2846
            // Is this an existing argument?
2847
0
            if (*index < FRAME.getArgCount()) {
2848
0
              O1REG(GetArgumentsPropByVal) = FRAME.getArgRef(*index);
2849
0
              ip = NEXTINST(GetArgumentsPropByVal);
2850
0
              DISPATCH;
2851
0
            }
2852
0
          }
2853
0
        }
2854
        // Slow path.
2855
0
        CAPTURE_IP_ASSIGN(
2856
0
            auto res,
2857
0
            getArgumentsPropByValSlowPath_RJS(
2858
0
                runtime,
2859
0
                &O3REG(GetArgumentsPropByVal),
2860
0
                &O2REG(GetArgumentsPropByVal),
2861
0
                FRAME.getCalleeClosureHandleUnsafe(),
2862
0
                strictMode));
2863
0
        if (res == ExecutionStatus::EXCEPTION) {
2864
0
          goto exception;
2865
0
        }
2866
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2867
0
        O1REG(GetArgumentsPropByVal) = res->getHermesValue();
2868
0
        ip = NEXTINST(GetArgumentsPropByVal);
2869
0
        DISPATCH;
2870
0
      }
2871
2872
0
      CASE(ReifyArguments) {
2873
        // If the arguments object was already created, do nothing.
2874
0
        if (!O1REG(ReifyArguments).isUndefined()) {
2875
0
          assert(
2876
0
              O1REG(ReifyArguments).isObject() &&
2877
0
              "arguments lazy register is not an object");
2878
0
          ip = NEXTINST(ReifyArguments);
2879
0
          DISPATCH;
2880
0
        }
2881
0
        CAPTURE_IP(
2882
0
            resArgs = reifyArgumentsSlowPath(
2883
0
                runtime, FRAME.getCalleeClosureHandleUnsafe(), strictMode));
2884
0
        if (LLVM_UNLIKELY(resArgs == ExecutionStatus::EXCEPTION)) {
2885
0
          goto exception;
2886
0
        }
2887
0
        O1REG(ReifyArguments) = resArgs->getHermesValue();
2888
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2889
0
        ip = NEXTINST(ReifyArguments);
2890
0
        DISPATCH;
2891
0
      }
2892
2893
376
      CASE(NewObject) {
2894
        // Create a new object using the built-in constructor. Note that the
2895
        // built-in constructor is empty, so we don't actually need to call
2896
        // it.
2897
376
        CAPTURE_IP(
2898
376
            O1REG(NewObject) = JSObject::create(runtime).getHermesValue());
2899
376
        assert(
2900
376
            gcScope.getHandleCountDbg() == KEEP_HANDLES &&
2901
376
            "Should not create handles.");
2902
376
        ip = NEXTINST(NewObject);
2903
1.88k
        DISPATCH;
2904
1.88k
      }
2905
0
      CASE(NewObjectWithParent) {
2906
0
        CAPTURE_IP(
2907
0
            O1REG(NewObjectWithParent) =
2908
0
                JSObject::create(
2909
0
                    runtime,
2910
0
                    O2REG(NewObjectWithParent).isObject()
2911
0
                        ? Handle<JSObject>::vmcast(&O2REG(NewObjectWithParent))
2912
0
                        : O2REG(NewObjectWithParent).isNull()
2913
0
                        ? Runtime::makeNullHandle<JSObject>()
2914
0
                        : Handle<JSObject>::vmcast(&runtime.objectPrototype))
2915
0
                    .getHermesValue());
2916
0
        assert(
2917
0
            gcScope.getHandleCountDbg() == KEEP_HANDLES &&
2918
0
            "Should not create handles.");
2919
0
        ip = NEXTINST(NewObjectWithParent);
2920
0
        DISPATCH;
2921
0
      }
2922
2923
0
      CASE(NewObjectWithBuffer) {
2924
0
        CAPTURE_IP(
2925
0
            resPH = Interpreter::createObjectFromBuffer(
2926
0
                runtime,
2927
0
                curCodeBlock,
2928
0
                ip->iNewObjectWithBuffer.op3,
2929
0
                ip->iNewObjectWithBuffer.op4,
2930
0
                ip->iNewObjectWithBuffer.op5));
2931
0
        if (LLVM_UNLIKELY(resPH == ExecutionStatus::EXCEPTION)) {
2932
0
          goto exception;
2933
0
        }
2934
0
        O1REG(NewObjectWithBuffer) = resPH->get();
2935
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2936
0
        ip = NEXTINST(NewObjectWithBuffer);
2937
0
        DISPATCH;
2938
0
      }
2939
2940
0
      CASE(NewObjectWithBufferLong) {
2941
0
        CAPTURE_IP(
2942
0
            resPH = Interpreter::createObjectFromBuffer(
2943
0
                runtime,
2944
0
                curCodeBlock,
2945
0
                ip->iNewObjectWithBufferLong.op3,
2946
0
                ip->iNewObjectWithBufferLong.op4,
2947
0
                ip->iNewObjectWithBufferLong.op5));
2948
0
        if (LLVM_UNLIKELY(resPH == ExecutionStatus::EXCEPTION)) {
2949
0
          goto exception;
2950
0
        }
2951
0
        O1REG(NewObjectWithBufferLong) = resPH->get();
2952
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2953
0
        ip = NEXTINST(NewObjectWithBufferLong);
2954
0
        DISPATCH;
2955
0
      }
2956
2957
95
      CASE(NewArray) {
2958
        // Create a new array using the built-in constructor. Note that the
2959
        // built-in constructor is empty, so we don't actually need to call
2960
        // it.
2961
95
        {
2962
95
          CAPTURE_IP_ASSIGN(
2963
95
              auto createRes,
2964
95
              JSArray::create(runtime, ip->iNewArray.op2, ip->iNewArray.op2));
2965
95
          if (createRes == ExecutionStatus::EXCEPTION) {
2966
0
            goto exception;
2967
0
          }
2968
95
          O1REG(NewArray) = createRes->getHermesValue();
2969
95
        }
2970
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2971
95
        ip = NEXTINST(NewArray);
2972
475
        DISPATCH;
2973
475
      }
2974
2975
6
      CASE(NewArrayWithBuffer) {
2976
6
        CAPTURE_IP(
2977
6
            resPH = Interpreter::createArrayFromBuffer(
2978
6
                runtime,
2979
6
                curCodeBlock,
2980
6
                ip->iNewArrayWithBuffer.op2,
2981
6
                ip->iNewArrayWithBuffer.op3,
2982
6
                ip->iNewArrayWithBuffer.op4));
2983
6
        if (LLVM_UNLIKELY(resPH == ExecutionStatus::EXCEPTION)) {
2984
0
          goto exception;
2985
0
        }
2986
6
        O1REG(NewArrayWithBuffer) = resPH->get();
2987
6
        gcScope.flushToSmallCount(KEEP_HANDLES);
2988
6
        tmpHandle.clear();
2989
6
        ip = NEXTINST(NewArrayWithBuffer);
2990
30
        DISPATCH;
2991
30
      }
2992
2993
0
      CASE(NewArrayWithBufferLong) {
2994
0
        CAPTURE_IP(
2995
0
            resPH = Interpreter::createArrayFromBuffer(
2996
0
                runtime,
2997
0
                curCodeBlock,
2998
0
                ip->iNewArrayWithBufferLong.op2,
2999
0
                ip->iNewArrayWithBufferLong.op3,
3000
0
                ip->iNewArrayWithBufferLong.op4));
3001
0
        if (LLVM_UNLIKELY(resPH == ExecutionStatus::EXCEPTION)) {
3002
0
          goto exception;
3003
0
        }
3004
0
        O1REG(NewArrayWithBufferLong) = resPH->get();
3005
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
3006
0
        tmpHandle.clear();
3007
0
        ip = NEXTINST(NewArrayWithBufferLong);
3008
0
        DISPATCH;
3009
0
      }
3010
3011
564
      CASE(CreateThis) {
3012
        // Registers: output, prototype, closure.
3013
564
        if (LLVM_UNLIKELY(!vmisa<Callable>(O3REG(CreateThis)))) {
3014
0
          CAPTURE_IP(runtime.raiseTypeError("constructor is not callable"));
3015
0
          goto exception;
3016
0
        }
3017
564
        CAPTURE_IP_ASSIGN(
3018
564
            auto res,
3019
564
            Callable::newObject(
3020
564
                Handle<Callable>::vmcast(&O3REG(CreateThis)),
3021
564
                runtime,
3022
564
                Handle<JSObject>::vmcast(
3023
564
                    O2REG(CreateThis).isObject() ? &O2REG(CreateThis)
3024
564
                                                 : &runtime.objectPrototype)));
3025
564
        if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
3026
0
          goto exception;
3027
0
        }
3028
564
        gcScope.flushToSmallCount(KEEP_HANDLES);
3029
564
        O1REG(CreateThis) = res->getHermesValue();
3030
564
        ip = NEXTINST(CreateThis);
3031
2.82k
        DISPATCH;
3032
2.82k
      }
3033
3034
564
      CASE(SelectObject) {
3035
        // Registers: output, thisObject, constructorReturnValue.
3036
564
        O1REG(SelectObject) = O3REG(SelectObject).isObject()
3037
564
            ? O3REG(SelectObject)
3038
564
            : O2REG(SelectObject);
3039
564
        ip = NEXTINST(SelectObject);
3040
2.82k
        DISPATCH;
3041
2.82k
      }
3042
3043
564
      CASE(Eq)
3044
512k
      CASE(Neq) {
3045
512k
        CAPTURE_IP_ASSIGN(
3046
512k
            auto eqRes,
3047
512k
            abstractEqualityTest_RJS(
3048
512k
                runtime, Handle<>(&O2REG(Eq)), Handle<>(&O3REG(Eq))));
3049
512k
        if (eqRes == ExecutionStatus::EXCEPTION) {
3050
0
          goto exception;
3051
0
        }
3052
512k
        gcScope.flushToSmallCount(KEEP_HANDLES);
3053
512k
        O1REG(Eq) = HermesValue::encodeBoolValue(
3054
512k
            ip->opCode == OpCode::Eq ? *eqRes : !*eqRes);
3055
512k
        ip = NEXTINST(Eq);
3056
2.56M
        DISPATCH;
3057
2.56M
      }
3058
0
      CASE(StrictEq) {
3059
0
        O1REG(StrictEq) = HermesValue::encodeBoolValue(
3060
0
            strictEqualityTest(O2REG(StrictEq), O3REG(StrictEq)));
3061
0
        ip = NEXTINST(StrictEq);
3062
0
        DISPATCH;
3063
0
      }
3064
0
      CASE(StrictNeq) {
3065
0
        O1REG(StrictNeq) = HermesValue::encodeBoolValue(
3066
0
            !strictEqualityTest(O2REG(StrictNeq), O3REG(StrictNeq)));
3067
0
        ip = NEXTINST(StrictNeq);
3068
0
        DISPATCH;
3069
0
      }
3070
1
      CASE(Not) {
3071
1
        O1REG(Not) = HermesValue::encodeBoolValue(!toBoolean(O2REG(Not)));
3072
1
        ip = NEXTINST(Not);
3073
5
        DISPATCH;
3074
5
      }
3075
7.13k
      CASE(Negate) {
3076
7.13k
        if (LLVM_LIKELY(O2REG(Negate).isNumber())) {
3077
7.05k
          O1REG(Negate) = HermesValue::encodeUntrustedNumberValue(
3078
7.05k
              -O2REG(Negate).getNumber());
3079
7.05k
          ip = NEXTINST(Negate);
3080
35.2k
          DISPATCH;
3081
35.2k
        }
3082
7.13k
        CAPTURE_IP(res = doNegateSlowPath(runtime, Handle<>(&O2REG(Negate))));
3083
7.13k
        if (res == ExecutionStatus::EXCEPTION)
3084
0
          goto exception;
3085
7.13k
        O1REG(Negate) = *res;
3086
7.13k
        gcScope.flushToSmallCount(KEEP_HANDLES);
3087
7.13k
        ip = NEXTINST(Negate);
3088
7.13k
        DISPATCH;
3089
410
      }
3090
1.12k
      CASE(TypeOf) {
3091
1.12k
        CAPTURE_IP(O1REG(TypeOf) = typeOf(runtime, Handle<>(&O2REG(TypeOf))));
3092
1.12k
        ip = NEXTINST(TypeOf);
3093
5.64k
        DISPATCH;
3094
5.64k
      }
3095
14
      CASE(Mod) {
3096
14
        if (LLVM_LIKELY(O2REG(Mod).isNumber() && O3REG(Mod).isNumber())) {
3097
          /* Fast-path. */
3098
13
          O1REG(Mod) = HermesValue::encodeUntrustedNumberValue(
3099
13
              doMod(O2REG(Mod).getNumber(), O3REG(Mod).getNumber()));
3100
13
          ip = NEXTINST(Mod);
3101
65
          DISPATCH;
3102
65
        }
3103
14
        CAPTURE_IP(
3104
14
            res = doOperSlowPath<doMod>(
3105
14
                runtime, Handle<>(&O2REG(Mod)), Handle<>(&O3REG(Mod))));
3106
14
        if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
3107
0
          goto exception;
3108
0
        }
3109
14
        O1REG(Mod) = *res;
3110
14
        gcScope.flushToSmallCount(KEEP_HANDLES);
3111
14
        ip = NEXTINST(Mod);
3112
14
        DISPATCH;
3113
5
      }
3114
0
      CASE(InstanceOf) {
3115
0
        CAPTURE_IP_ASSIGN(
3116
0
            auto result,
3117
0
            instanceOfOperator_RJS(
3118
0
                runtime,
3119
0
                Handle<>(&O2REG(InstanceOf)),
3120
0
                Handle<>(&O3REG(InstanceOf))));
3121
0
        if (LLVM_UNLIKELY(result == ExecutionStatus::EXCEPTION)) {
3122
0
          goto exception;
3123
0
        }
3124
0
        O1REG(InstanceOf) = HermesValue::encodeBoolValue(*result);
3125
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
3126
0
        ip = NEXTINST(InstanceOf);
3127
0
        DISPATCH;
3128
0
      }
3129
0
      CASE(IsIn) {
3130
0
        {
3131
0
          if (LLVM_UNLIKELY(!O3REG(IsIn).isObject())) {
3132
0
            CAPTURE_IP(runtime.raiseTypeError(
3133
0
                "right operand of 'in' is not an object"));
3134
0
            goto exception;
3135
0
          }
3136
0
          CAPTURE_IP_ASSIGN(
3137
0
              auto cr,
3138
0
              JSObject::hasComputed(
3139
0
                  Handle<JSObject>::vmcast(&O3REG(IsIn)),
3140
0
                  runtime,
3141
0
                  Handle<>(&O2REG(IsIn))));
3142
0
          if (cr == ExecutionStatus::EXCEPTION) {
3143
0
            goto exception;
3144
0
          }
3145
0
          O1REG(IsIn) = HermesValue::encodeBoolValue(*cr);
3146
0
        }
3147
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
3148
0
        ip = NEXTINST(IsIn);
3149
0
        DISPATCH;
3150
0
      }
3151
3152
188
      CASE(PutNewOwnByIdShort) {
3153
188
        nextIP = NEXTINST(PutNewOwnByIdShort);
3154
188
        idVal = ip->iPutNewOwnByIdShort.op3;
3155
188
        goto putOwnById;
3156
0
      }
3157
0
      CASE(PutNewOwnNEByIdLong)
3158
0
      CASE(PutNewOwnByIdLong) {
3159
0
        nextIP = NEXTINST(PutNewOwnByIdLong);
3160
0
        idVal = ip->iPutNewOwnByIdLong.op3;
3161
0
        goto putOwnById;
3162
0
      }
3163
0
      CASE(PutNewOwnNEById)
3164
0
      CASE(PutNewOwnById) {
3165
0
        nextIP = NEXTINST(PutNewOwnById);
3166
0
        idVal = ip->iPutNewOwnById.op3;
3167
0
      }
3168
188
    putOwnById: {
3169
188
      assert(
3170
188
          O1REG(PutNewOwnById).isObject() &&
3171
188
          "Object argument of PutNewOwnById must be an object");
3172
188
      CAPTURE_IP_ASSIGN(
3173
188
          auto res,
3174
188
          JSObject::defineNewOwnProperty(
3175
188
              Handle<JSObject>::vmcast(&O1REG(PutNewOwnById)),
3176
188
              runtime,
3177
188
              ID(idVal),
3178
188
              ip->opCode <= OpCode::PutNewOwnByIdLong
3179
188
                  ? PropertyFlags::defaultNewNamedPropertyFlags()
3180
188
                  : PropertyFlags::nonEnumerablePropertyFlags(),
3181
188
              Handle<>(&O2REG(PutNewOwnById))));
3182
188
      if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
3183
0
        goto exception;
3184
0
      }
3185
188
      gcScope.flushToSmallCount(KEEP_HANDLES);
3186
188
      ip = nextIP;
3187
940
      DISPATCH;
3188
940
    }
3189
3190
0
      CASE(DelByIdLong) {
3191
0
        idVal = ip->iDelByIdLong.op3;
3192
0
        nextIP = NEXTINST(DelByIdLong);
3193
0
        goto DelById;
3194
940
      }
3195
3196
273
      CASE(DelById) {
3197
273
        idVal = ip->iDelById.op3;
3198
273
        nextIP = NEXTINST(DelById);
3199
273
      }
3200
273
    DelById: {
3201
273
      if (LLVM_LIKELY(O2REG(DelById).isObject())) {
3202
273
        CAPTURE_IP_ASSIGN(
3203
273
            auto status,
3204
273
            JSObject::deleteNamed(
3205
273
                Handle<JSObject>::vmcast(&O2REG(DelById)),
3206
273
                runtime,
3207
273
                ID(idVal),
3208
273
                defaultPropOpFlags));
3209
273
        if (LLVM_UNLIKELY(status == ExecutionStatus::EXCEPTION)) {
3210
0
          goto exception;
3211
0
        }
3212
273
        O1REG(DelById) = HermesValue::encodeBoolValue(status.getValue());
3213
273
      } else {
3214
        // This is the "slow path".
3215
0
        CAPTURE_IP(res = toObject(runtime, Handle<>(&O2REG(DelById))));
3216
0
        if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
3217
          // If an exception is thrown, likely we are trying to convert
3218
          // undefined/null to an object. Passing over the name of the property
3219
          // so that we could emit more meaningful error messages.
3220
0
          CAPTURE_IP(amendPropAccessErrorMsgWithPropName(
3221
0
              runtime, Handle<>(&O2REG(DelById)), "delete", ID(idVal)));
3222
0
          goto exception;
3223
0
        }
3224
0
        tmpHandle = res.getValue();
3225
0
        CAPTURE_IP_ASSIGN(
3226
0
            auto status,
3227
0
            JSObject::deleteNamed(
3228
0
                Handle<JSObject>::vmcast(tmpHandle),
3229
0
                runtime,
3230
0
                ID(idVal),
3231
0
                defaultPropOpFlags));
3232
0
        if (LLVM_UNLIKELY(status == ExecutionStatus::EXCEPTION)) {
3233
0
          goto exception;
3234
0
        }
3235
0
        O1REG(DelById) = HermesValue::encodeBoolValue(status.getValue());
3236
0
        tmpHandle.clear();
3237
0
      }
3238
273
      gcScope.flushToSmallCount(KEEP_HANDLES);
3239
273
      ip = nextIP;
3240
1.36k
      DISPATCH;
3241
1.36k
    }
3242
3243
0
      CASE(DelByVal) {
3244
0
        if (LLVM_LIKELY(O2REG(DelByVal).isObject())) {
3245
0
          CAPTURE_IP_ASSIGN(
3246
0
              auto status,
3247
0
              JSObject::deleteComputed(
3248
0
                  Handle<JSObject>::vmcast(&O2REG(DelByVal)),
3249
0
                  runtime,
3250
0
                  Handle<>(&O3REG(DelByVal)),
3251
0
                  defaultPropOpFlags));
3252
0
          if (LLVM_UNLIKELY(status == ExecutionStatus::EXCEPTION)) {
3253
0
            goto exception;
3254
0
          }
3255
0
          O1REG(DelByVal) = HermesValue::encodeBoolValue(status.getValue());
3256
0
        } else {
3257
          // This is the "slow path".
3258
0
          CAPTURE_IP(res = toObject(runtime, Handle<>(&O2REG(DelByVal))));
3259
0
          if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
3260
0
            goto exception;
3261
0
          }
3262
0
          tmpHandle = res.getValue();
3263
0
          CAPTURE_IP_ASSIGN(
3264
0
              auto status,
3265
0
              JSObject::deleteComputed(
3266
0
                  Handle<JSObject>::vmcast(tmpHandle),
3267
0
                  runtime,
3268
0
                  Handle<>(&O3REG(DelByVal)),
3269
0
                  defaultPropOpFlags));
3270
0
          if (LLVM_UNLIKELY(status == ExecutionStatus::EXCEPTION)) {
3271
0
            goto exception;
3272
0
          }
3273
0
          O1REG(DelByVal) = HermesValue::encodeBoolValue(status.getValue());
3274
0
        }
3275
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
3276
0
        tmpHandle.clear();
3277
0
        ip = NEXTINST(DelByVal);
3278
0
        DISPATCH;
3279
0
      }
3280
1.03k
      CASE(CreateRegExp) {
3281
1.03k
        {
3282
          // Create the RegExp object.
3283
1.03k
          CAPTURE_IP(
3284
1.03k
              O1REG(CreateRegExp) = JSRegExp::create(runtime).getHermesValue());
3285
1.03k
          auto re = Handle<JSRegExp>::vmcast(&O1REG(CreateRegExp));
3286
          // Initialize the regexp.
3287
1.03k
          CAPTURE_IP_ASSIGN(
3288
1.03k
              auto pattern,
3289
1.03k
              runtime.makeHandle(curCodeBlock->getRuntimeModule()
3290
1.03k
                                     ->getStringPrimFromStringIDMayAllocate(
3291
1.03k
                                         ip->iCreateRegExp.op2)));
3292
1.03k
          CAPTURE_IP_ASSIGN(
3293
1.03k
              auto flags,
3294
1.03k
              runtime.makeHandle(curCodeBlock->getRuntimeModule()
3295
1.03k
                                     ->getStringPrimFromStringIDMayAllocate(
3296
1.03k
                                         ip->iCreateRegExp.op3)));
3297
1.03k
          CAPTURE_IP_ASSIGN(
3298
1.03k
              auto bytecode,
3299
1.03k
              curCodeBlock->getRuntimeModule()->getRegExpBytecodeFromRegExpID(
3300
1.03k
                  ip->iCreateRegExp.op4));
3301
1.03k
          CAPTURE_IP(
3302
1.03k
              JSRegExp::initialize(re, runtime, pattern, flags, bytecode));
3303
1.03k
        }
3304
1.03k
        gcScope.flushToSmallCount(KEEP_HANDLES);
3305
1.03k
        ip = NEXTINST(CreateRegExp);
3306
5.16k
        DISPATCH;
3307
5.16k
      }
3308
3309
0
      CASE(SwitchImm) {
3310
0
        if (LLVM_LIKELY(O1REG(SwitchImm).isNumber())) {
3311
0
          double numVal = O1REG(SwitchImm).getNumber();
3312
0
          uint32_t uintVal = (uint32_t)numVal;
3313
0
          if (LLVM_LIKELY(numVal == uintVal) && // Only integers.
3314
0
              LLVM_LIKELY(uintVal >= ip->iSwitchImm.op4) && // Bounds checking.
3315
0
              LLVM_LIKELY(uintVal <= ip->iSwitchImm.op5)) // Bounds checking.
3316
0
          {
3317
            // Calculate the offset into the bytecode where the jump table for
3318
            // this SwitchImm starts.
3319
0
            const uint8_t *tablestart = (const uint8_t *)llvh::alignAddr(
3320
0
                (const uint8_t *)ip + ip->iSwitchImm.op2, sizeof(uint32_t));
3321
3322
            // Read the offset from the table.
3323
            // Must be signed to account for backwards branching.
3324
0
            const int32_t *loc =
3325
0
                (const int32_t *)tablestart + uintVal - ip->iSwitchImm.op4;
3326
3327
0
            ip = IPADD(*loc);
3328
0
            DISPATCH;
3329
0
          }
3330
0
        }
3331
        // Wrong type or out of range, jump to default.
3332
0
        ip = IPADD(ip->iSwitchImm.op3);
3333
0
        DISPATCH;
3334
0
      }
3335
800k
      LOAD_CONST(
3336
800k
          LoadConstUInt8,
3337
800k
          HermesValue::encodeTrustedNumberValue(ip->iLoadConstUInt8.op2));
3338
3.15M
      LOAD_CONST(
3339
3.15M
          LoadConstInt,
3340
3.15M
          HermesValue::encodeTrustedNumberValue(ip->iLoadConstInt.op2));
3341
3.15M
      LOAD_CONST(
3342
41.3k
          LoadConstDouble,
3343
41.3k
          HermesValue::encodeUntrustedNumberValue(ip->iLoadConstDouble.op2));
3344
3.80M
      LOAD_CONST_CAPTURE_IP(
3345
3.80M
          LoadConstString,
3346
3.80M
          HermesValue::encodeStringValue(
3347
3.80M
              curCodeBlock->getRuntimeModule()
3348
3.80M
                  ->getStringPrimFromStringIDMayAllocate(
3349
3.80M
                      ip->iLoadConstString.op2)));
3350
3.80M
      LOAD_CONST_CAPTURE_IP(
3351
0
          LoadConstStringLongIndex,
3352
0
          HermesValue::encodeStringValue(
3353
0
              curCodeBlock->getRuntimeModule()
3354
0
                  ->getStringPrimFromStringIDMayAllocate(
3355
0
                      ip->iLoadConstStringLongIndex.op2)));
3356
0
      LOAD_CONST(LoadConstEmpty, HermesValue::encodeEmptyValue());
3357
10.4k
      LOAD_CONST(LoadConstUndefined, HermesValue::encodeUndefinedValue());
3358
10.4k
      LOAD_CONST(LoadConstNull, HermesValue::encodeNullValue());
3359
4.51k
      LOAD_CONST(LoadConstTrue, HermesValue::encodeBoolValue(true));
3360
1.18k
      LOAD_CONST(LoadConstFalse, HermesValue::encodeBoolValue(false));
3361
2.31M
      LOAD_CONST(LoadConstZero, HermesValue::encodeTrustedNumberValue(0));
3362
2.31M
      CASE(LoadConstBigInt) {
3363
511k
        idVal = ip->iLoadConstBigInt.op2;
3364
511k
        nextIP = NEXTINST(LoadConstBigInt);
3365
511k
        goto doLoadConstBigInt;
3366
2.31M
      }
3367
0
      CASE(LoadConstBigIntLongIndex) {
3368
0
        idVal = ip->iLoadConstBigIntLongIndex.op2;
3369
0
        nextIP = NEXTINST(LoadConstBigIntLongIndex);
3370
0
        goto doLoadConstBigInt;
3371
2.31M
      }
3372
511k
    doLoadConstBigInt: {
3373
511k
      CAPTURE_IP_ASSIGN(
3374
511k
          auto res,
3375
511k
          BigIntPrimitive::fromBytes(
3376
511k
              runtime,
3377
511k
              curCodeBlock->getRuntimeModule()->getBigIntBytesFromBigIntId(
3378
511k
                  idVal)));
3379
511k
      if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
3380
0
        goto exception;
3381
0
      }
3382
      // It is safe to access O1REG(LoadConstBigInt) or
3383
      // O1REG(LoadConstBigIntLongIndex) here as both instructions' O1 operands
3384
      // are the same size and live in the same offset w.r.t. the start of the
3385
      // instruction.
3386
511k
      O1REG(LoadConstBigInt) = std::move(*res);
3387
511k
      ip = nextIP;
3388
2.55M
      DISPATCH;
3389
2.55M
    }
3390
511k
      BINOP(Sub);
3391
366
      BINOP(Mul);
3392
11
      BINOP(Div);
3393
      // Can't do BINOP(Mod) as there's no ModN opcode.
3394
11
      BITWISEBINOP(BitAnd);
3395
0
      BITWISEBINOP(BitOr);
3396
0
      BITWISEBINOP(BitXor);
3397
0
      SHIFTOP(LShift);
3398
0
      SHIFTOP(RShift);
3399
0
      SHIFTOP(URshift);
3400
4.09M
      CONDOP(Less, <, lessOp_RJS);
3401
4.09M
      CONDOP(LessEq, <=, lessEqualOp_RJS);
3402
0
      CONDOP(Greater, >, greaterOp_RJS);
3403
0
      CONDOP(GreaterEq, >=, greaterEqualOp_RJS);
3404
0
      JCOND(Less, <, lessOp_RJS);
3405
0
      JCOND(LessEqual, <=, lessEqualOp_RJS);
3406
0
      JCOND(Greater, >, greaterOp_RJS);
3407
0
      JCOND(GreaterEqual, >=, greaterEqualOp_RJS);
3408
3409
1.12k
      JCOND_STRICT_EQ_IMPL(
3410
1.12k
          JStrictEqual, , IPADD(ip->iJStrictEqual.op1), NEXTINST(JStrictEqual));
3411
1.12k
      JCOND_STRICT_EQ_IMPL(
3412
0
          JStrictEqual,
3413
0
          Long,
3414
0
          IPADD(ip->iJStrictEqualLong.op1),
3415
0
          NEXTINST(JStrictEqualLong));
3416
2.25k
      JCOND_STRICT_EQ_IMPL(
3417
2.25k
          JStrictNotEqual,
3418
2.25k
          ,
3419
2.25k
          NEXTINST(JStrictNotEqual),
3420
2.25k
          IPADD(ip->iJStrictNotEqual.op1));
3421
2.25k
      JCOND_STRICT_EQ_IMPL(
3422
0
          JStrictNotEqual,
3423
0
          Long,
3424
0
          NEXTINST(JStrictNotEqualLong),
3425
0
          IPADD(ip->iJStrictNotEqualLong.op1));
3426
3427
1.50k
      JCOND_EQ_IMPL(JEqual, , IPADD(ip->iJEqual.op1), NEXTINST(JEqual));
3428
1.50k
      JCOND_EQ_IMPL(
3429
0
          JEqual, Long, IPADD(ip->iJEqualLong.op1), NEXTINST(JEqualLong));
3430
0
      JCOND_EQ_IMPL(
3431
0
          JNotEqual, , NEXTINST(JNotEqual), IPADD(ip->iJNotEqual.op1));
3432
0
      JCOND_EQ_IMPL(
3433
0
          JNotEqual,
3434
0
          Long,
3435
0
          NEXTINST(JNotEqualLong),
3436
0
          IPADD(ip->iJNotEqualLong.op1));
3437
3438
0
      CASE_OUTOFLINE(PutOwnByVal);
3439
0
      CASE_OUTOFLINE(PutOwnGetterSetterByVal);
3440
0
      CASE_OUTOFLINE(DirectEval);
3441
3442
0
      CASE_OUTOFLINE(IteratorBegin);
3443
0
      CASE_OUTOFLINE(IteratorNext);
3444
0
      CASE(IteratorClose) {
3445
0
        if (LLVM_UNLIKELY(O1REG(IteratorClose).isObject())) {
3446
          // The iterator must be closed if it's still an object.
3447
          // That means it was never an index and is not done iterating (a state
3448
          // which is indicated by `undefined`).
3449
0
          CAPTURE_IP_ASSIGN(
3450
0
              auto res,
3451
0
              iteratorClose(
3452
0
                  runtime,
3453
0
                  Handle<JSObject>::vmcast(&O1REG(IteratorClose)),
3454
0
                  Runtime::getEmptyValue()));
3455
0
          if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
3456
0
            if (ip->iIteratorClose.op2 &&
3457
0
                !isUncatchableError(runtime.thrownValue_)) {
3458
              // Ignore inner exception.
3459
0
              runtime.clearThrownValue();
3460
0
            } else {
3461
0
              goto exception;
3462
0
            }
3463
0
          }
3464
0
          gcScope.flushToSmallCount(KEEP_HANDLES);
3465
0
        }
3466
0
        ip = NEXTINST(IteratorClose);
3467
0
        DISPATCH;
3468
0
      }
3469
3470
#ifdef HERMES_RUN_WASM
3471
      // Asm.js/Wasm Intrinsics
3472
      CASE(Add32) {
3473
        O1REG(Add32) = HermesValue::encodeUntrustedNumberValue(
3474
            (int32_t)(int64_t)(O2REG(Add32).getNumber() +
3475
                               O3REG(Add32).getNumber()));
3476
        ip = NEXTINST(Add32);
3477
        DISPATCH;
3478
      }
3479
      CASE(Sub32) {
3480
        O1REG(Sub32) = HermesValue::encodeUntrustedNumberValue(
3481
            (int32_t)(int64_t)(O2REG(Sub32).getNumber() -
3482
                               O3REG(Sub32).getNumber()));
3483
        ip = NEXTINST(Sub32);
3484
        DISPATCH;
3485
      }
3486
      CASE(Mul32) {
3487
        // Signedness matters for multiplication, but low 32 bits are the same
3488
        // regardless of signedness.
3489
        const uint32_t arg0 = (uint32_t)(int32_t)(O2REG(Mul32).getNumber());
3490
        const uint32_t arg1 = (uint32_t)(int32_t)(O3REG(Mul32).getNumber());
3491
        O1REG(Mul32) =
3492
            HermesValue::encodeUntrustedNumberValue((int32_t)(arg0 * arg1));
3493
        ip = NEXTINST(Mul32);
3494
        DISPATCH;
3495
      }
3496
      CASE(Divi32) {
3497
        const int32_t arg0 = (int32_t)(O2REG(Divi32).getNumber());
3498
        const int32_t arg1 = (int32_t)(O3REG(Divi32).getNumber());
3499
        O1REG(Divi32) = HermesValue::encodeUntrustedNumberValue(arg0 / arg1);
3500
        ip = NEXTINST(Divi32);
3501
        DISPATCH;
3502
      }
3503
      CASE(Divu32) {
3504
        const uint32_t arg0 = (uint32_t)(int32_t)(O2REG(Divu32).getNumber());
3505
        const uint32_t arg1 = (uint32_t)(int32_t)(O3REG(Divu32).getNumber());
3506
        O1REG(Divu32) =
3507
            HermesValue::encodeUntrustedNumberValue((int32_t)(arg0 / arg1));
3508
        ip = NEXTINST(Divu32);
3509
        DISPATCH;
3510
      }
3511
3512
      CASE(Loadi8) {
3513
        auto *mem = vmcast<JSTypedArrayBase>(O2REG(Loadi8));
3514
        int8_t *basePtr = reinterpret_cast<int8_t *>(mem->begin(runtime));
3515
        const uint32_t addr = (uint32_t)(int32_t)(O3REG(Loadi8).getNumber());
3516
        O1REG(Loadi8) = HermesValue::encodeUntrustedNumberValue(basePtr[addr]);
3517
        ip = NEXTINST(Loadi8);
3518
        DISPATCH;
3519
      }
3520
      CASE(Loadu8) {
3521
        auto *mem = vmcast<JSTypedArrayBase>(O2REG(Loadu8));
3522
        uint8_t *basePtr = reinterpret_cast<uint8_t *>(mem->begin(runtime));
3523
        const uint32_t addr = (uint32_t)(int32_t)(O3REG(Loadu8).getNumber());
3524
        O1REG(Loadu8) = HermesValue::encodeUntrustedNumberValue(basePtr[addr]);
3525
        ip = NEXTINST(Loadu8);
3526
        DISPATCH;
3527
      }
3528
      CASE(Loadi16) {
3529
        auto *mem = vmcast<JSTypedArrayBase>(O2REG(Loadi16));
3530
        int16_t *basePtr = reinterpret_cast<int16_t *>(mem->begin(runtime));
3531
        const uint32_t addr = (uint32_t)(int32_t)(O3REG(Loadi16).getNumber());
3532
        O1REG(Loadi16) =
3533
            HermesValue::encodeUntrustedNumberValue(basePtr[addr >> 1]);
3534
        ip = NEXTINST(Loadi16);
3535
        DISPATCH;
3536
      }
3537
      CASE(Loadu16) {
3538
        auto *mem = vmcast<JSTypedArrayBase>(O2REG(Loadu16));
3539
        uint16_t *basePtr = reinterpret_cast<uint16_t *>(mem->begin(runtime));
3540
        const uint32_t addr = (uint32_t)(int32_t)(O3REG(Loadu16).getNumber());
3541
        O1REG(Loadu16) =
3542
            HermesValue::encodeUntrustedNumberValue(basePtr[addr >> 1]);
3543
        ip = NEXTINST(Loadu16);
3544
        DISPATCH;
3545
      }
3546
      CASE(Loadi32) {
3547
        auto *mem = vmcast<JSTypedArrayBase>(O2REG(Loadi32));
3548
        int32_t *basePtr = reinterpret_cast<int32_t *>(mem->begin(runtime));
3549
        const uint32_t addr = (uint32_t)(int32_t)(O3REG(Loadi32).getNumber());
3550
        O1REG(Loadi32) =
3551
            HermesValue::encodeUntrustedNumberValue(basePtr[addr >> 2]);
3552
        ip = NEXTINST(Loadi32);
3553
        DISPATCH;
3554
      }
3555
      CASE(Loadu32) {
3556
        auto *mem = vmcast<JSTypedArrayBase>(O2REG(Loadu32));
3557
        uint32_t *basePtr = reinterpret_cast<uint32_t *>(mem->begin(runtime));
3558
        const uint32_t addr = (uint32_t)(int32_t)(O3REG(Loadu32).getNumber());
3559
        O1REG(Loadu32) = HermesValue::encodeUntrustedNumberValue(
3560
            (int32_t)(basePtr[addr >> 2]));
3561
        ip = NEXTINST(Loadu32);
3562
        DISPATCH;
3563
      }
3564
3565
      CASE(Store8) {
3566
        auto *mem = vmcast<JSTypedArrayBase>(O1REG(Store8));
3567
        int8_t *basePtr = reinterpret_cast<int8_t *>(mem->begin(runtime));
3568
        const uint32_t addr = (uint32_t)(int32_t)(O2REG(Store8).getNumber());
3569
        basePtr[addr] = (int8_t)(int32_t)(O3REG(Store8).getNumber());
3570
        ip = NEXTINST(Store8);
3571
        DISPATCH;
3572
      }
3573
      CASE(Store16) {
3574
        auto *mem = vmcast<JSTypedArrayBase>(O1REG(Store16));
3575
        int16_t *basePtr = reinterpret_cast<int16_t *>(mem->begin(runtime));
3576
        const uint32_t addr = (uint32_t)(int32_t)(O2REG(Store16).getNumber());
3577
        basePtr[addr >> 1] = (int16_t)(int32_t)(O3REG(Store16).getNumber());
3578
        ip = NEXTINST(Store16);
3579
        DISPATCH;
3580
      }
3581
      CASE(Store32) {
3582
        auto *mem = vmcast<JSTypedArrayBase>(O1REG(Store32));
3583
        int32_t *basePtr = reinterpret_cast<int32_t *>(mem->begin(runtime));
3584
        const uint32_t addr = (uint32_t)(int32_t)(O2REG(Store32).getNumber());
3585
        basePtr[addr >> 2] = (int32_t)(O3REG(Store32).getNumber());
3586
        // A nop for now.
3587
        ip = NEXTINST(Store32);
3588
        DISPATCH;
3589
      }
3590
#endif
3591
3592
0
      CASE(_last) {
3593
0
        hermes_fatal("Invalid opcode _last");
3594
0
      }
3595
0
    }
3596
3597
0
    hermes_fatal(
3598
0
        "All opcodes should dispatch to the next and not fallthrough "
3599
0
        "to here");
3600
3601
  // We arrive here if we couldn't allocate the registers for the current frame.
3602
0
  stackOverflow:
3603
0
    CAPTURE_IP(runtime.raiseStackOverflow(
3604
0
        Runtime::StackOverflowKind::JSRegisterStack));
3605
3606
  // We arrive here when we raised an exception in a callee, but we don't want
3607
  // the callee to be able to handle it.
3608
0
  handleExceptionInParent:
3609
    // Restore the caller code block and IP.
3610
0
    curCodeBlock = FRAME.getSavedCodeBlock();
3611
0
    ip = FRAME.getSavedIP();
3612
3613
    // Pop to the previous frame where technically the error happened.
3614
0
    frameRegs = &runtime.restoreStackAndPreviousFrame(FRAME).getFirstLocalRef();
3615
3616
    // If we are coming from native code, return.
3617
0
    if (!curCodeBlock)
3618
0
      return ExecutionStatus::EXCEPTION;
3619
3620
  // Handle the exception.
3621
30
  exception:
3622
30
    UPDATE_OPCODE_TIME_SPENT;
3623
30
    assert(
3624
30
        !runtime.thrownValue_.isEmpty() &&
3625
30
        "thrownValue unavailable at exception");
3626
3627
30
    bool catchable = true;
3628
    // If this is an Error object that was thrown internally, it didn't have
3629
    // access to the current codeblock and IP, so collect the stack trace here.
3630
30
    if (auto *jsError = dyn_vmcast<JSError>(runtime.thrownValue_)) {
3631
30
      catchable = jsError->catchable();
3632
30
      if (!jsError->getStackTrace()) {
3633
        // Temporarily clear the thrown value for following operations.
3634
26
        CAPTURE_IP_ASSIGN(
3635
26
            auto errorHandle,
3636
26
            runtime.makeHandle(vmcast<JSError>(runtime.thrownValue_)));
3637
26
        runtime.clearThrownValue();
3638
3639
26
        CAPTURE_IP(
3640
26
            JSError::recordStackTrace(
3641
26
                errorHandle, runtime, false, curCodeBlock, ip));
3642
3643
        // Restore the thrown value.
3644
26
        runtime.setThrownValue(errorHandle.getHermesValue());
3645
26
      }
3646
30
    }
3647
3648
30
    gcScope.flushToSmallCount(KEEP_HANDLES);
3649
30
    tmpHandle.clear();
3650
3651
30
#ifdef HERMES_ENABLE_DEBUGGER
3652
30
    if (SingleStep) {
3653
      // If we're single stepping, don't bother with any more checks,
3654
      // and simply signal that we should continue execution with an exception.
3655
0
      state.codeBlock = curCodeBlock;
3656
0
      state.offset = CUROFFSET;
3657
0
      return ExecutionStatus::EXCEPTION;
3658
0
    }
3659
3660
30
    using PauseOnThrowMode = facebook::hermes::debugger::PauseOnThrowMode;
3661
30
    auto mode = runtime.debugger_.getPauseOnThrowMode();
3662
30
    if (mode != PauseOnThrowMode::None) {
3663
0
      if (!runtime.debugger_.isDebugging()) {
3664
        // Determine whether the PauseOnThrowMode requires us to stop here.
3665
0
        bool caught =
3666
0
            runtime.debugger_
3667
0
                .findCatchTarget(InterpreterState(curCodeBlock, CUROFFSET))
3668
0
                .hasValue();
3669
0
        bool shouldStop = mode == PauseOnThrowMode::All ||
3670
0
            (mode == PauseOnThrowMode::Uncaught && !caught);
3671
0
        if (shouldStop) {
3672
          // When runDebugger is invoked after an exception,
3673
          // stepping should never happen internally.
3674
          // Any step is a step to an exception handler, which we do
3675
          // directly here in the interpreter.
3676
          // Thus, the result state should be the same as the input state.
3677
0
          InterpreterState tmpState{curCodeBlock, (uint32_t)CUROFFSET};
3678
0
          CAPTURE_IP_ASSIGN(
3679
0
              ExecutionStatus resultStatus,
3680
0
              runtime.debugger_.runDebugger(
3681
0
                  Debugger::RunReason::Exception, tmpState));
3682
0
          (void)resultStatus;
3683
0
          assert(
3684
0
              tmpState == InterpreterState(curCodeBlock, CUROFFSET) &&
3685
0
              "not allowed to step internally in a pauseOnThrow");
3686
0
          gcScope.flushToSmallCount(KEEP_HANDLES);
3687
0
        }
3688
0
      }
3689
0
    }
3690
30
#endif
3691
3692
30
    int32_t handlerOffset = 0;
3693
3694
    // If the exception is not catchable, skip found catch blocks.
3695
30
    while (((handlerOffset = curCodeBlock->findCatchTargetOffset(CUROFFSET)) ==
3696
30
            -1) ||
3697
30
           !catchable) {
3698
30
      PROFILER_EXIT_FUNCTION(curCodeBlock);
3699
3700
30
#ifdef HERMES_MEMORY_INSTRUMENTATION
3701
30
      runtime.popCallStack();
3702
30
#endif
3703
3704
      // Restore the code block and IP.
3705
30
      curCodeBlock = FRAME.getSavedCodeBlock();
3706
30
      ip = FRAME.getSavedIP();
3707
3708
      // Pop a stack frame.
3709
30
      frameRegs =
3710
30
          &runtime.restoreStackAndPreviousFrame(FRAME).getFirstLocalRef();
3711
3712
30
      SLOW_DEBUG(
3713
30
          dbgs() << "function exit with exception: restored stackLevel="
3714
30
                 << runtime.getStackLevel() << "\n");
3715
3716
      // Are we returning to native code?
3717
30
      if (!curCodeBlock) {
3718
30
        SLOW_DEBUG(
3719
30
            dbgs()
3720
30
            << "function exit with exception: returning to native code\n");
3721
30
        return ExecutionStatus::EXCEPTION;
3722
30
      }
3723
3724
30
      assert(
3725
0
          isCallType(ip->opCode) &&
3726
0
          "return address is not Call-type instruction");
3727
0
    }
3728
3729
0
    INIT_STATE_FOR_CODEBLOCK(curCodeBlock);
3730
3731
0
    ip = IPADD(handlerOffset - CUROFFSET);
3732
0
  }
3733
1.64k
}
hermes::vm::CallResult<hermes::vm::HermesValue, (hermes::vm::detail::CallResultSpecialize)2> hermes::vm::Interpreter::interpretFunction<false, false>(hermes::vm::Runtime&, hermes::vm::InterpreterState&)
Line
Count
Source
838
231
    InterpreterState &state) {
839
  // The interpreter is re-entrant and also saves/restores its IP via the
840
  // runtime whenever a call out is made (see the CAPTURE_IP_* macros). As such,
841
  // failure to preserve the IP across calls to interpreterFunction() disrupt
842
  // interpreter calls further up the C++ callstack. The RAII utility class
843
  // below makes sure we always do this correctly.
844
  //
845
  // TODO: The IPs stored in the C++ callstack via this holder will generally be
846
  // the same as in the JS stack frames via the Saved IP field. We can probably
847
  // get rid of one of these redundant stores. Doing this isn't completely
848
  // trivial as there are currently cases where we re-enter the interpreter
849
  // without calling Runtime::saveCallerIPInStackFrame(), and there are features
850
  // (I think mostly the debugger + stack traces) which implicitly rely on
851
  // this behavior. At least their tests break if this behavior is not
852
  // preserved.
853
231
  struct IPSaver {
854
231
    IPSaver(Runtime &runtime)
855
231
        : ip_(runtime.getCurrentIP()), runtime_(runtime) {}
856
857
231
    ~IPSaver() {
858
231
      runtime_.setCurrentIP(ip_);
859
231
    }
860
861
231
   private:
862
231
    const Inst *ip_;
863
231
    Runtime &runtime_;
864
231
  };
865
231
  IPSaver ipSaver(runtime);
866
867
#ifndef HERMES_ENABLE_DEBUGGER
868
  static_assert(!SingleStep, "can't use single-step mode without the debugger");
869
#endif
870
  // Make sure that the cache can use an optimization by avoiding a branch to
871
  // access the property storage.
872
231
  static_assert(
873
231
      HiddenClass::kDictionaryThreshold <=
874
231
          SegmentedArray::kValueToSegmentThreshold,
875
231
      "Cannot avoid branches in cache check if the dictionary "
876
231
      "crossover point is larger than the inline storage");
877
878
231
  CodeBlock *curCodeBlock = state.codeBlock;
879
231
  const Inst *ip = nullptr;
880
  // Points to the first local register in the current frame.
881
  // This eliminates the indirect load from Runtime and the -1 offset.
882
231
  PinnedHermesValue *frameRegs;
883
  // Strictness of current function.
884
231
  bool strictMode;
885
  // Default flags when accessing properties.
886
231
  PropOpFlags defaultPropOpFlags;
887
888
// These CAPTURE_IP* macros should wrap around any major calls out of the
889
// interpreter loop. They stash and retrieve the IP via the current Runtime
890
// allowing the IP to be externally observed and even altered to change the flow
891
// of execution. Explicitly saving AND restoring the IP from the Runtime in this
892
// way means the C++ compiler will keep IP in a register within the rest of the
893
// interpreter loop.
894
//
895
// When assertions are enabled we take the extra step of "invalidating" the IP
896
// between captures so we can detect if it's erroneously accessed.
897
//
898
#ifdef NDEBUG
899
900
#define CAPTURE_IP(expr)    \
901
  runtime.setCurrentIP(ip); \
902
  (void)(expr);             \
903
  ip = runtime.getCurrentIP();
904
905
// Used when we want to declare a new variable and assign the expression to it.
906
#define CAPTURE_IP_ASSIGN(decl, expr) \
907
  runtime.setCurrentIP(ip);           \
908
  decl = (expr);                      \
909
  ip = runtime.getCurrentIP();
910
911
#else // !NDEBUG
912
913
231
#define CAPTURE_IP(expr)       \
914
231
  runtime.setCurrentIP(ip);    \
915
231
  (void)(expr);                \
916
231
  ip = runtime.getCurrentIP(); \
917
231
  runtime.invalidateCurrentIP();
918
919
// Used when we want to declare a new variable and assign the expression to it.
920
231
#define CAPTURE_IP_ASSIGN(decl, expr) \
921
231
  runtime.setCurrentIP(ip);           \
922
231
  decl = (expr);                      \
923
231
  ip = runtime.getCurrentIP();        \
924
231
  runtime.invalidateCurrentIP();
925
926
231
#endif // NDEBUG
927
928
/// \def DONT_CAPTURE_IP(expr)
929
/// \param expr A call expression to a function external to the interpreter. The
930
///   expression should not make any allocations and the IP should be set
931
///   immediately following this macro.
932
231
#define DONT_CAPTURE_IP(expr)      \
933
231
  do {                             \
934
231
    NoAllocScope noAlloc(runtime); \
935
231
    (void)expr;                    \
936
231
  } while (false)
937
938
// When performing a tail call, we need to set the runtime IP and leave it set.
939
231
#define CAPTURE_IP_SET() runtime.setCurrentIP(ip)
940
941
231
  LLVM_DEBUG(dbgs() << "interpretFunction() called\n");
942
943
231
  ScopedNativeDepthTracker depthTracker{runtime};
944
231
  if (LLVM_UNLIKELY(depthTracker.overflowed())) {
945
0
    return runtime.raiseStackOverflow(Runtime::StackOverflowKind::NativeStack);
946
0
  }
947
948
231
  GCScope gcScope(runtime);
949
  // Avoid allocating a handle dynamically by reusing this one.
950
231
  MutableHandle<> tmpHandle(runtime);
951
231
  CallResult<HermesValue> res{ExecutionStatus::EXCEPTION};
952
231
  CallResult<PseudoHandle<>> resPH{ExecutionStatus::EXCEPTION};
953
231
  CallResult<Handle<Arguments>> resArgs{ExecutionStatus::EXCEPTION};
954
231
  CallResult<bool> boolRes{ExecutionStatus::EXCEPTION};
955
  // Start of the bytecode file, used to calculate IP offset in crash traces.
956
231
  const uint8_t *bytecodeFileStart;
957
958
  // Mark the gcScope so we can clear all allocated handles.
959
  // Remember how many handles the scope has so we can clear them in the loop.
960
231
  static constexpr unsigned KEEP_HANDLES = 1;
961
231
  assert(
962
231
      gcScope.getHandleCountDbg() == KEEP_HANDLES &&
963
231
      "scope has unexpected number of handles");
964
965
231
  INIT_OPCODE_PROFILER;
966
967
1.64k
tailCall:
968
1.64k
  PROFILER_ENTER_FUNCTION(curCodeBlock);
969
970
1.64k
#ifdef HERMES_ENABLE_DEBUGGER
971
1.64k
  runtime.getDebugger().willEnterCodeBlock(curCodeBlock);
972
1.64k
#endif
973
974
1.64k
  runtime.getCodeCoverageProfiler().markExecuted(curCodeBlock);
975
976
1.64k
  if (!SingleStep) {
977
1.64k
    auto newFrame = runtime.setCurrentFrameToTopOfStack();
978
1.64k
    runtime.saveCallerIPInStackFrame();
979
1.64k
#ifndef NDEBUG
980
1.64k
    runtime.invalidateCurrentIP();
981
1.64k
#endif
982
983
    // Point frameRegs to the first register in the new frame. Note that at this
984
    // moment technically it points above the top of the stack, but we are never
985
    // going to access it.
986
1.64k
    frameRegs = &newFrame.getFirstLocalRef();
987
988
1.64k
#ifndef NDEBUG
989
1.64k
    LLVM_DEBUG(
990
1.64k
        dbgs() << "function entry: stackLevel=" << runtime.getStackLevel()
991
1.64k
               << ", argCount=" << runtime.getCurrentFrame().getArgCount()
992
1.64k
               << ", frameSize=" << curCodeBlock->getFrameSize() << "\n");
993
994
1.64k
    LLVM_DEBUG(
995
1.64k
        dbgs() << " callee "
996
1.64k
               << DumpHermesValue(
997
1.64k
                      runtime.getCurrentFrame().getCalleeClosureOrCBRef())
998
1.64k
               << "\n");
999
1.64k
    LLVM_DEBUG(
1000
1.64k
        dbgs() << "   this "
1001
1.64k
               << DumpHermesValue(runtime.getCurrentFrame().getThisArgRef())
1002
1.64k
               << "\n");
1003
2.76k
    for (uint32_t i = 0; i != runtime.getCurrentFrame()->getArgCount(); ++i) {
1004
1.12k
      LLVM_DEBUG(
1005
1.12k
          dbgs() << "   " << llvh::format_decimal(i, 4) << " "
1006
1.12k
                 << DumpHermesValue(runtime.getCurrentFrame().getArgRef(i))
1007
1.12k
                 << "\n");
1008
1.12k
    }
1009
1.64k
#endif
1010
1011
    // Allocate the registers for the new frame.
1012
1.64k
    if (LLVM_UNLIKELY(!runtime.checkAndAllocStack(
1013
1.64k
            curCodeBlock->getFrameSize() +
1014
1.64k
                StackFrameLayout::CalleeExtraRegistersAtStart,
1015
1.64k
            HermesValue::encodeUndefinedValue())))
1016
0
      goto stackOverflow;
1017
1018
1.64k
    ip = (Inst const *)curCodeBlock->begin();
1019
1020
    // Check for invalid invocation.
1021
1.64k
    if (LLVM_UNLIKELY(curCodeBlock->getHeaderFlags().isCallProhibited(
1022
1.64k
            newFrame.isConstructorCall()))) {
1023
0
      if (!newFrame.isConstructorCall()) {
1024
0
        CAPTURE_IP(
1025
0
            runtime.raiseTypeError("Class constructor invoked without new"));
1026
0
      } else {
1027
0
        CAPTURE_IP(runtime.raiseTypeError("Function is not a constructor"));
1028
0
      }
1029
0
      goto handleExceptionInParent;
1030
0
    }
1031
1.64k
  } else {
1032
    // Point frameRegs to the first register in the frame.
1033
0
    frameRegs = &runtime.getCurrentFrame().getFirstLocalRef();
1034
0
    ip = (Inst const *)(curCodeBlock->begin() + state.offset);
1035
0
  }
1036
1037
1.64k
  assert((const uint8_t *)ip < curCodeBlock->end() && "CodeBlock is empty");
1038
1039
1.64k
  INIT_STATE_FOR_CODEBLOCK(curCodeBlock);
1040
1041
1.64k
#define BEFORE_OP_CODE                                                       \
1042
1.64k
  {                                                                          \
1043
1.64k
    UPDATE_OPCODE_TIME_SPENT;                                                \
1044
1.64k
    HERMES_SLOW_ASSERT(                                                      \
1045
1.64k
        curCodeBlock->contains(ip) && "curCodeBlock must contain ip");       \
1046
1.64k
    HERMES_SLOW_ASSERT((printDebugInfo(curCodeBlock, frameRegs, ip), true)); \
1047
1.64k
    HERMES_SLOW_ASSERT(                                                      \
1048
1.64k
        gcScope.getHandleCountDbg() == KEEP_HANDLES &&                       \
1049
1.64k
        "unaccounted handles were created");                                 \
1050
1.64k
    HERMES_SLOW_ASSERT(tmpHandle->isUndefined() && "tmpHandle not cleared"); \
1051
1.64k
    RECORD_OPCODE_START_TIME;                                                \
1052
1.64k
    INC_OPCODE_COUNT;                                                        \
1053
1.64k
    if (EnableCrashTrace) {                                                  \
1054
1.64k
      runtime.crashTrace_.recordInst(                                        \
1055
1.64k
          (uint32_t)((const uint8_t *)ip - bytecodeFileStart), ip->opCode);  \
1056
1.64k
    }                                                                        \
1057
1.64k
  }
1058
1059
1.64k
#ifdef HERMESVM_INDIRECT_THREADING
1060
1.64k
  static void *opcodeDispatch[] = {
1061
1.64k
#define DEFINE_OPCODE(name) &&case_##name,
1062
1.64k
#include "hermes/BCGen/HBC/BytecodeList.def"
1063
1.64k
      &&case__last};
1064
1065
1.64k
#define CASE(name) case_##name:
1066
// For indirect threading, there is no way to specify a default, leave it as
1067
// an empty label.
1068
1.64k
#define DEFAULT_CASE
1069
1.64k
#define DISPATCH                                \
1070
1.64k
  BEFORE_OP_CODE;                               \
1071
1.64k
  if (SingleStep) {                             \
1072
1.64k
    state.codeBlock = curCodeBlock;             \
1073
1.64k
    state.offset = CUROFFSET;                   \
1074
1.64k
    return HermesValue::encodeUndefinedValue(); \
1075
1.64k
  }                                             \
1076
1.64k
  goto *opcodeDispatch[(unsigned)ip->opCode]
1077
1078
// Do nothing if we're not in a switch.
1079
1.64k
#define INTERPRETER_FALLTHROUGH
1080
1081
#else // HERMESVM_INDIRECT_THREADING
1082
1083
#define CASE(name) case OpCode::name:
1084
#define DEFAULT_CASE default:
1085
#define DISPATCH                                \
1086
  if (SingleStep) {                             \
1087
    state.codeBlock = curCodeBlock;             \
1088
    state.offset = CUROFFSET;                   \
1089
    return HermesValue::encodeUndefinedValue(); \
1090
  }                                             \
1091
  continue
1092
1093
// Fallthrough if we're in a switch.
1094
#define INTERPRETER_FALLTHROUGH [[fallthrough]]
1095
1096
#endif // HERMESVM_INDIRECT_THREADING
1097
1098
// This macro is used when we detect that either the Implicit or Explicit
1099
// AsyncBreak flags have been set. It checks to see which one was requested and
1100
// propagate the corresponding RunReason. If both Implicit and Explicit have
1101
// been requested, then we'll propagate the RunReasons for both. Once for
1102
// Implicit and once for Explicit.
1103
1.64k
#define RUN_DEBUGGER_ASYNC_BREAK(flags)                         \
1104
1.64k
  bool requestedImplicit = (uint8_t)(flags) &                   \
1105
1.64k
      (uint8_t)Runtime::AsyncBreakReasonBits::DebuggerImplicit; \
1106
1.64k
  bool requestedExplicit = (uint8_t)(flags) &                   \
1107
1.64k
      (uint8_t)Runtime::AsyncBreakReasonBits::DebuggerExplicit; \
1108
1.64k
  do {                                                          \
1109
1.64k
    if (requestedImplicit) {                                    \
1110
1.64k
      CAPTURE_IP_ASSIGN(                                        \
1111
1.64k
          auto dRes,                                            \
1112
1.64k
          runDebuggerUpdatingState(                             \
1113
1.64k
              Debugger::RunReason::AsyncBreakImplicit,          \
1114
1.64k
              runtime,                                          \
1115
1.64k
              curCodeBlock,                                     \
1116
1.64k
              ip,                                               \
1117
1.64k
              frameRegs));                                      \
1118
1.64k
      if (dRes == ExecutionStatus::EXCEPTION)                   \
1119
1.64k
        goto exception;                                         \
1120
1.64k
    }                                                           \
1121
1.64k
    if (requestedExplicit) {                                    \
1122
1.64k
      CAPTURE_IP_ASSIGN(                                        \
1123
1.64k
          auto dRes,                                            \
1124
1.64k
          runDebuggerUpdatingState(                             \
1125
1.64k
              Debugger::RunReason::AsyncBreakExplicit,          \
1126
1.64k
              runtime,                                          \
1127
1.64k
              curCodeBlock,                                     \
1128
1.64k
              ip,                                               \
1129
1.64k
              frameRegs));                                      \
1130
1.64k
      if (dRes == ExecutionStatus::EXCEPTION)                   \
1131
1.64k
        goto exception;                                         \
1132
1.64k
    }                                                           \
1133
1.64k
  } while (0)
1134
1135
1.64k
  for (;;) {
1136
6.56k
    BEFORE_OP_CODE;
1137
1138
6.56k
#ifdef HERMESVM_INDIRECT_THREADING
1139
6.56k
    goto *opcodeDispatch[(unsigned)ip->opCode];
1140
#else
1141
    switch (ip->opCode)
1142
#endif
1143
6.56k
    {
1144
6.56k
      const Inst *nextIP;
1145
6.56k
      uint32_t idVal;
1146
6.56k
      bool tryProp;
1147
6.56k
      uint32_t callArgCount;
1148
      // This is HermesValue::getRaw(), since HermesValue cannot be assigned
1149
      // to. It is meant to be used only for very short durations, in the
1150
      // dispatch of call instructions, when there is definitely no possibility
1151
      // of a GC.
1152
6.56k
      HermesValue::RawType callNewTarget;
1153
1154
/// Handle an opcode \p name with an out-of-line implementation in a function
1155
///   ExecutionStatus caseName(
1156
///       Runtime &,
1157
///       PinnedHermesValue *frameRegs,
1158
///       Inst *ip)
1159
6.56k
#define CASE_OUTOFLINE(name)                                         \
1160
6.56k
  CASE(name) {                                                       \
1161
6.56k
    CAPTURE_IP_ASSIGN(auto res, case##name(runtime, frameRegs, ip)); \
1162
6.56k
    if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {          \
1163
6.56k
      goto exception;                                                \
1164
6.56k
    }                                                                \
1165
6.56k
    gcScope.flushToSmallCount(KEEP_HANDLES);                         \
1166
6.56k
    ip = NEXTINST(name);                                             \
1167
6.56k
    DISPATCH;                                                        \
1168
6.56k
  }
1169
1170
/// Implement a binary arithmetic instruction with a fast path where both
1171
/// operands are numbers.
1172
/// \param name the name of the instruction. The fast path case will have a
1173
///     "n" appended to the name.
1174
6.56k
#define BINOP(name)                                                      \
1175
6.56k
  CASE(name) {                                                           \
1176
6.56k
    if (LLVM_LIKELY(O2REG(name).isNumber() && O3REG(name).isNumber())) { \
1177
      /* Fast-path. */                                                   \
1178
6.56k
      INTERPRETER_FALLTHROUGH;                                           \
1179
6.56k
      CASE(name##N) {                                                    \
1180
6.56k
        O1REG(name) = HermesValue::encodeTrustedNumberValue(             \
1181
6.56k
            do##name(O2REG(name).getNumber(), O3REG(name).getNumber())); \
1182
6.56k
        ip = NEXTINST(name);                                             \
1183
6.56k
        DISPATCH;                                                        \
1184
6.56k
      }                                                                  \
1185
6.56k
    }                                                                    \
1186
6.56k
    CAPTURE_IP(                                                          \
1187
6.56k
        res = doOperSlowPath<do##name>(                                  \
1188
6.56k
            runtime, Handle<>(&O2REG(name)), Handle<>(&O3REG(name))));   \
1189
6.56k
    if (res == ExecutionStatus::EXCEPTION)                               \
1190
6.56k
      goto exception;                                                    \
1191
6.56k
    O1REG(name) = *res;                                                  \
1192
6.56k
    gcScope.flushToSmallCount(KEEP_HANDLES);                             \
1193
6.56k
    ip = NEXTINST(name);                                                 \
1194
6.56k
    DISPATCH;                                                            \
1195
6.56k
  }
1196
1197
6.56k
#define INCDECOP(name)                                                        \
1198
6.56k
  CASE(name) {                                                                \
1199
6.56k
    if (LLVM_LIKELY(O2REG(name).isNumber())) {                                \
1200
6.56k
      O1REG(name) = HermesValue::encodeTrustedNumberValue(                    \
1201
6.56k
          do##name(O2REG(name).getNumber()));                                 \
1202
6.56k
      ip = NEXTINST(name);                                                    \
1203
6.56k
      DISPATCH;                                                               \
1204
6.56k
    }                                                                         \
1205
6.56k
    CAPTURE_IP(                                                               \
1206
6.56k
        res =                                                                 \
1207
6.56k
            doIncDecOperSlowPath<do##name>(runtime, Handle<>(&O2REG(name)))); \
1208
6.56k
    if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {                   \
1209
6.56k
      goto exception;                                                         \
1210
6.56k
    }                                                                         \
1211
6.56k
    O1REG(name) = *res;                                                       \
1212
6.56k
    gcScope.flushToSmallCount(KEEP_HANDLES);                                  \
1213
6.56k
    ip = NEXTINST(name);                                                      \
1214
6.56k
    DISPATCH;                                                                 \
1215
6.56k
  }
1216
1217
/// Implement a shift instruction with a fast path where both
1218
/// operands are numbers.
1219
/// \param name the name of the instruction.
1220
6.56k
#define SHIFTOP(name)                                                          \
1221
6.56k
  CASE(name) {                                                                 \
1222
6.56k
    if (LLVM_LIKELY(                                                           \
1223
6.56k
            O2REG(name).isNumber() &&                                          \
1224
6.56k
            O3REG(name).isNumber())) { /* Fast-path. */                        \
1225
6.56k
      auto lnum = hermes::truncateToInt32(O2REG(name).getNumber());            \
1226
6.56k
      uint32_t rnum = hermes::truncateToInt32(O3REG(name).getNumber()) & 0x1f; \
1227
6.56k
      O1REG(name) =                                                            \
1228
6.56k
          HermesValue::encodeTrustedNumberValue(do##name(lnum, rnum));         \
1229
6.56k
      ip = NEXTINST(name);                                                     \
1230
6.56k
      DISPATCH;                                                                \
1231
6.56k
    }                                                                          \
1232
6.56k
    CAPTURE_IP(                                                                \
1233
6.56k
        res = doShiftOperSlowPath<do##name>(                                   \
1234
6.56k
            runtime, Handle<>(&O2REG(name)), Handle<>(&O3REG(name))));         \
1235
6.56k
    if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {                    \
1236
6.56k
      goto exception;                                                          \
1237
6.56k
    }                                                                          \
1238
6.56k
    O1REG(name) = *res;                                                        \
1239
6.56k
    gcScope.flushToSmallCount(KEEP_HANDLES);                                   \
1240
6.56k
    ip = NEXTINST(name);                                                       \
1241
6.56k
    DISPATCH;                                                                  \
1242
6.56k
  }
1243
1244
/// Implement a binary bitwise instruction with a fast path where both
1245
/// operands are numbers.
1246
/// \param name the name of the instruction.
1247
6.56k
#define BITWISEBINOP(name)                                               \
1248
6.56k
  CASE(name) {                                                           \
1249
6.56k
    if (LLVM_LIKELY(O2REG(name).isNumber() && O3REG(name).isNumber())) { \
1250
      /* Fast-path. */                                                   \
1251
6.56k
      O1REG(name) = HermesValue::encodeTrustedNumberValue(               \
1252
6.56k
          do##name(                                                      \
1253
6.56k
              hermes::truncateToInt32(O2REG(name).getNumber()),          \
1254
6.56k
              hermes::truncateToInt32(O3REG(name).getNumber())));        \
1255
6.56k
      ip = NEXTINST(name);                                               \
1256
6.56k
      DISPATCH;                                                          \
1257
6.56k
    }                                                                    \
1258
6.56k
    CAPTURE_IP(                                                          \
1259
6.56k
        res = doBitOperSlowPath<do##name>(                               \
1260
6.56k
            runtime, Handle<>(&O2REG(name)), Handle<>(&O3REG(name))));   \
1261
6.56k
    if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {              \
1262
6.56k
      goto exception;                                                    \
1263
6.56k
    }                                                                    \
1264
6.56k
    O1REG(name) = *res;                                                  \
1265
6.56k
    gcScope.flushToSmallCount(KEEP_HANDLES);                             \
1266
6.56k
    ip = NEXTINST(name);                                                 \
1267
6.56k
    DISPATCH;                                                            \
1268
6.56k
  }
1269
1270
/// Implement a comparison instruction.
1271
/// \param name the name of the instruction.
1272
/// \param oper the C++ operator to use to actually perform the fast arithmetic
1273
///     comparison.
1274
/// \param operFuncName  function to call for the slow-path comparison.
1275
6.56k
#define CONDOP(name, oper, operFuncName)                                 \
1276
6.56k
  CASE(name) {                                                           \
1277
6.56k
    if (LLVM_LIKELY(O2REG(name).isNumber() && O3REG(name).isNumber())) { \
1278
      /* Fast-path. */                                                   \
1279
6.56k
      O1REG(name) = HermesValue::encodeBoolValue(                        \
1280
6.56k
          O2REG(name).getNumber() oper O3REG(name).getNumber());         \
1281
6.56k
      ip = NEXTINST(name);                                               \
1282
6.56k
      DISPATCH;                                                          \
1283
6.56k
    }                                                                    \
1284
6.56k
    CAPTURE_IP(                                                          \
1285
6.56k
        boolRes = operFuncName(                                          \
1286
6.56k
            runtime, Handle<>(&O2REG(name)), Handle<>(&O3REG(name))));   \
1287
6.56k
    if (boolRes == ExecutionStatus::EXCEPTION)                           \
1288
6.56k
      goto exception;                                                    \
1289
6.56k
    gcScope.flushToSmallCount(KEEP_HANDLES);                             \
1290
6.56k
    O1REG(name) = HermesValue::encodeBoolValue(boolRes.getValue());      \
1291
6.56k
    ip = NEXTINST(name);                                                 \
1292
6.56k
    DISPATCH;                                                            \
1293
6.56k
  }
1294
1295
/// Implement a comparison conditional jump with a fast path where both
1296
/// operands are numbers.
1297
/// \param name the name of the instruction. The fast path case will have a
1298
///     "N" appended to the name.
1299
/// \param suffix  Optional suffix to be added to the end (e.g. Long)
1300
/// \param oper the C++ operator to use to actually perform the fast arithmetic
1301
///     comparison.
1302
/// \param operFuncName  function to call for the slow-path comparison.
1303
/// \param trueDest  ip value if the conditional evaluates to true
1304
/// \param falseDest  ip value if the conditional evaluates to false
1305
6.56k
#define JCOND_IMPL(name, suffix, oper, operFuncName, trueDest, falseDest) \
1306
6.56k
  CASE(name##suffix) {                                                    \
1307
6.56k
    if (LLVM_LIKELY(                                                      \
1308
6.56k
            O2REG(name##suffix).isNumber() &&                             \
1309
6.56k
            O3REG(name##suffix).isNumber())) {                            \
1310
      /* Fast-path. */                                                    \
1311
6.56k
      INTERPRETER_FALLTHROUGH;                                            \
1312
6.56k
      CASE(name##N##suffix) {                                             \
1313
6.56k
        if (O2REG(name##N##suffix)                                        \
1314
6.56k
                .getNumber() oper O3REG(name##N##suffix)                  \
1315
6.56k
                .getNumber()) {                                           \
1316
6.56k
          ip = trueDest;                                                  \
1317
6.56k
          DISPATCH;                                                       \
1318
6.56k
        }                                                                 \
1319
6.56k
        ip = falseDest;                                                   \
1320
6.56k
        DISPATCH;                                                         \
1321
6.56k
      }                                                                   \
1322
6.56k
    }                                                                     \
1323
6.56k
    CAPTURE_IP(                                                           \
1324
6.56k
        boolRes = operFuncName(                                           \
1325
6.56k
            runtime,                                                      \
1326
6.56k
            Handle<>(&O2REG(name##suffix)),                               \
1327
6.56k
            Handle<>(&O3REG(name##suffix))));                             \
1328
6.56k
    if (boolRes == ExecutionStatus::EXCEPTION)                            \
1329
6.56k
      goto exception;                                                     \
1330
6.56k
    gcScope.flushToSmallCount(KEEP_HANDLES);                              \
1331
6.56k
    if (boolRes.getValue()) {                                             \
1332
6.56k
      ip = trueDest;                                                      \
1333
6.56k
      DISPATCH;                                                           \
1334
6.56k
    }                                                                     \
1335
6.56k
    ip = falseDest;                                                       \
1336
6.56k
    DISPATCH;                                                             \
1337
6.56k
  }
1338
1339
/// Implement a strict equality conditional jump
1340
/// \param name the name of the instruction.
1341
/// \param suffix  Optional suffix to be added to the end (e.g. Long)
1342
/// \param trueDest  ip value if the conditional evaluates to true
1343
/// \param falseDest  ip value if the conditional evaluates to false
1344
6.56k
#define JCOND_STRICT_EQ_IMPL(name, suffix, trueDest, falseDest)         \
1345
6.56k
  CASE(name##suffix) {                                                  \
1346
6.56k
    if (strictEqualityTest(O2REG(name##suffix), O3REG(name##suffix))) { \
1347
6.56k
      ip = trueDest;                                                    \
1348
6.56k
      DISPATCH;                                                         \
1349
6.56k
    }                                                                   \
1350
6.56k
    ip = falseDest;                                                     \
1351
6.56k
    DISPATCH;                                                           \
1352
6.56k
  }
1353
1354
/// Implement an equality conditional jump
1355
/// \param name the name of the instruction.
1356
/// \param suffix  Optional suffix to be added to the end (e.g. Long)
1357
/// \param trueDest  ip value if the conditional evaluates to true
1358
/// \param falseDest  ip value if the conditional evaluates to false
1359
6.56k
#define JCOND_EQ_IMPL(name, suffix, trueDest, falseDest) \
1360
6.56k
  CASE(name##suffix) {                                   \
1361
6.56k
    CAPTURE_IP_ASSIGN(                                   \
1362
6.56k
        auto eqRes,                                      \
1363
6.56k
        abstractEqualityTest_RJS(                        \
1364
6.56k
            runtime,                                     \
1365
6.56k
            Handle<>(&O2REG(name##suffix)),              \
1366
6.56k
            Handle<>(&O3REG(name##suffix))));            \
1367
6.56k
    if (eqRes == ExecutionStatus::EXCEPTION) {           \
1368
6.56k
      goto exception;                                    \
1369
6.56k
    }                                                    \
1370
6.56k
    gcScope.flushToSmallCount(KEEP_HANDLES);             \
1371
6.56k
    if (*eqRes) {                                        \
1372
6.56k
      ip = trueDest;                                     \
1373
6.56k
      DISPATCH;                                          \
1374
6.56k
    }                                                    \
1375
6.56k
    ip = falseDest;                                      \
1376
6.56k
    DISPATCH;                                            \
1377
6.56k
  }
1378
1379
/// Implement the long and short forms of a conditional jump, and its negation.
1380
6.56k
#define JCOND(name, oper, operFuncName) \
1381
6.56k
  JCOND_IMPL(                           \
1382
6.56k
      J##name,                          \
1383
6.56k
      ,                                 \
1384
6.56k
      oper,                             \
1385
6.56k
      operFuncName,                     \
1386
6.56k
      IPADD(ip->iJ##name.op1),          \
1387
6.56k
      NEXTINST(J##name));               \
1388
6.56k
  JCOND_IMPL(                           \
1389
6.56k
      J##name,                          \
1390
6.56k
      Long,                             \
1391
6.56k
      oper,                             \
1392
6.56k
      operFuncName,                     \
1393
6.56k
      IPADD(ip->iJ##name##Long.op1),    \
1394
6.56k
      NEXTINST(J##name##Long));         \
1395
6.56k
  JCOND_IMPL(                           \
1396
6.56k
      JNot##name,                       \
1397
6.56k
      ,                                 \
1398
6.56k
      oper,                             \
1399
6.56k
      operFuncName,                     \
1400
6.56k
      NEXTINST(JNot##name),             \
1401
6.56k
      IPADD(ip->iJNot##name.op1));      \
1402
6.56k
  JCOND_IMPL(                           \
1403
6.56k
      JNot##name,                       \
1404
6.56k
      Long,                             \
1405
6.56k
      oper,                             \
1406
6.56k
      operFuncName,                     \
1407
6.56k
      NEXTINST(JNot##name##Long),       \
1408
6.56k
      IPADD(ip->iJNot##name##Long.op1));
1409
1410
/// Load a constant.
1411
/// \param value is the value to store in the output register.
1412
6.56k
#define LOAD_CONST(name, value) \
1413
6.56k
  CASE(name) {                  \
1414
6.56k
    O1REG(name) = value;        \
1415
6.56k
    ip = NEXTINST(name);        \
1416
6.56k
    DISPATCH;                   \
1417
6.56k
  }
1418
1419
6.56k
#define LOAD_CONST_CAPTURE_IP(name, value) \
1420
6.56k
  CASE(name) {                             \
1421
6.56k
    CAPTURE_IP(O1REG(name) = value);       \
1422
6.56k
    ip = NEXTINST(name);                   \
1423
6.56k
    DISPATCH;                              \
1424
6.56k
  }
1425
1426
1.02M
      CASE(Mov) {
1427
1.02M
        O1REG(Mov) = O2REG(Mov);
1428
1.02M
        ip = NEXTINST(Mov);
1429
5.12M
        DISPATCH;
1430
5.12M
      }
1431
1432
467k
      CASE(MovLong) {
1433
467k
        O1REG(MovLong) = O2REG(MovLong);
1434
467k
        ip = NEXTINST(MovLong);
1435
2.33M
        DISPATCH;
1436
2.33M
      }
1437
1438
1.69k
      CASE(LoadParam) {
1439
1.69k
        if (LLVM_LIKELY(ip->iLoadParam.op2 <= FRAME.getArgCount())) {
1440
          // index 0 must load 'this'. Index 1 the first argument, etc.
1441
1.69k
          O1REG(LoadParam) = FRAME.getArgRef((int32_t)ip->iLoadParam.op2 - 1);
1442
1.69k
          ip = NEXTINST(LoadParam);
1443
8.46k
          DISPATCH;
1444
8.46k
        }
1445
1.69k
        O1REG(LoadParam) = HermesValue::encodeUndefinedValue();
1446
1.69k
        ip = NEXTINST(LoadParam);
1447
1.69k
        DISPATCH;
1448
0
      }
1449
1450
0
      CASE(LoadParamLong) {
1451
0
        if (LLVM_LIKELY(ip->iLoadParamLong.op2 <= FRAME.getArgCount())) {
1452
          // index 0 must load 'this'. Index 1 the first argument, etc.
1453
0
          O1REG(LoadParamLong) =
1454
0
              FRAME.getArgRef((int32_t)ip->iLoadParamLong.op2 - 1);
1455
0
          ip = NEXTINST(LoadParamLong);
1456
0
          DISPATCH;
1457
0
        }
1458
0
        O1REG(LoadParamLong) = HermesValue::encodeUndefinedValue();
1459
0
        ip = NEXTINST(LoadParamLong);
1460
0
        DISPATCH;
1461
0
      }
1462
1463
0
      CASE(CoerceThisNS) {
1464
0
        if (LLVM_LIKELY(O2REG(CoerceThisNS).isObject())) {
1465
0
          O1REG(CoerceThisNS) = O2REG(CoerceThisNS);
1466
0
        } else if (
1467
0
            O2REG(CoerceThisNS).isNull() || O2REG(CoerceThisNS).isUndefined()) {
1468
0
          O1REG(CoerceThisNS) = runtime.global_;
1469
0
        } else {
1470
0
          tmpHandle = O2REG(CoerceThisNS);
1471
0
          nextIP = NEXTINST(CoerceThisNS);
1472
0
          goto coerceThisSlowPath;
1473
0
        }
1474
0
        ip = NEXTINST(CoerceThisNS);
1475
0
        DISPATCH;
1476
0
      }
1477
9
      CASE(LoadThisNS) {
1478
9
        if (LLVM_LIKELY(FRAME.getThisArgRef().isObject())) {
1479
9
          O1REG(LoadThisNS) = FRAME.getThisArgRef();
1480
9
        } else if (
1481
0
            FRAME.getThisArgRef().isNull() ||
1482
0
            FRAME.getThisArgRef().isUndefined()) {
1483
0
          O1REG(LoadThisNS) = runtime.global_;
1484
0
        } else {
1485
0
          tmpHandle = FRAME.getThisArgRef();
1486
0
          nextIP = NEXTINST(LoadThisNS);
1487
0
          goto coerceThisSlowPath;
1488
0
        }
1489
9
        ip = NEXTINST(LoadThisNS);
1490
45
        DISPATCH;
1491
45
      }
1492
0
    coerceThisSlowPath: {
1493
0
      CAPTURE_IP(res = toObject(runtime, tmpHandle));
1494
0
      if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
1495
0
        goto exception;
1496
0
      }
1497
0
      O1REG(CoerceThisNS) = res.getValue();
1498
0
      tmpHandle.clear();
1499
0
      gcScope.flushToSmallCount(KEEP_HANDLES);
1500
0
      ip = nextIP;
1501
0
      DISPATCH;
1502
0
    }
1503
1504
0
      CASE(ConstructLong) {
1505
0
        callArgCount = (uint32_t)ip->iConstructLong.op3;
1506
0
        nextIP = NEXTINST(ConstructLong);
1507
0
        callNewTarget = O2REG(ConstructLong).getRaw();
1508
0
        goto doCall;
1509
0
      }
1510
7
      CASE(CallLong) {
1511
7
        callArgCount = (uint32_t)ip->iCallLong.op3;
1512
7
        nextIP = NEXTINST(CallLong);
1513
7
        callNewTarget = HermesValue::encodeUndefinedValue().getRaw();
1514
7
        goto doCall;
1515
0
      }
1516
1517
      // Note in Call1 through Call4, the first argument is 'this' which has
1518
      // argument index -1.
1519
      // Also note that we are writing to callNewTarget last, to avoid the
1520
      // possibility of it being aliased by the arg writes.
1521
658
      CASE(Call1) {
1522
658
        callArgCount = 1;
1523
658
        nextIP = NEXTINST(Call1);
1524
658
        StackFramePtr fr{runtime.stackPointer_};
1525
658
        fr.getArgRefUnsafe(-1) = O3REG(Call1);
1526
658
        callNewTarget = HermesValue::encodeUndefinedValue().getRaw();
1527
658
        goto doCall;
1528
0
      }
1529
1530
752
      CASE(Call2) {
1531
752
        callArgCount = 2;
1532
752
        nextIP = NEXTINST(Call2);
1533
752
        StackFramePtr fr{runtime.stackPointer_};
1534
752
        fr.getArgRefUnsafe(-1) = O3REG(Call2);
1535
752
        fr.getArgRefUnsafe(0) = O4REG(Call2);
1536
752
        callNewTarget = HermesValue::encodeUndefinedValue().getRaw();
1537
752
        goto doCall;
1538
0
      }
1539
1540
0
      CASE(Call3) {
1541
0
        callArgCount = 3;
1542
0
        nextIP = NEXTINST(Call3);
1543
0
        StackFramePtr fr{runtime.stackPointer_};
1544
0
        fr.getArgRefUnsafe(-1) = O3REG(Call3);
1545
0
        fr.getArgRefUnsafe(0) = O4REG(Call3);
1546
0
        fr.getArgRefUnsafe(1) = O5REG(Call3);
1547
0
        callNewTarget = HermesValue::encodeUndefinedValue().getRaw();
1548
0
        goto doCall;
1549
0
      }
1550
1551
0
      CASE(Call4) {
1552
0
        callArgCount = 4;
1553
0
        nextIP = NEXTINST(Call4);
1554
0
        StackFramePtr fr{runtime.stackPointer_};
1555
0
        fr.getArgRefUnsafe(-1) = O3REG(Call4);
1556
0
        fr.getArgRefUnsafe(0) = O4REG(Call4);
1557
0
        fr.getArgRefUnsafe(1) = O5REG(Call4);
1558
0
        fr.getArgRefUnsafe(2) = O6REG(Call4);
1559
0
        callNewTarget = HermesValue::encodeUndefinedValue().getRaw();
1560
0
        goto doCall;
1561
0
      }
1562
1563
564
      CASE(Construct) {
1564
564
        callArgCount = (uint32_t)ip->iConstruct.op3;
1565
564
        nextIP = NEXTINST(Construct);
1566
564
        callNewTarget = O2REG(Construct).getRaw();
1567
564
        goto doCall;
1568
0
      }
1569
86
      CASE(Call) {
1570
86
        callArgCount = (uint32_t)ip->iCall.op3;
1571
86
        nextIP = NEXTINST(Call);
1572
86
        callNewTarget = HermesValue::encodeUndefinedValue().getRaw();
1573
86
        goto doCall;
1574
0
      }
1575
1576
2.06k
    doCall: {
1577
2.06k
#ifdef HERMES_ENABLE_DEBUGGER
1578
      // Check for an async debugger request.
1579
2.06k
      if (uint8_t asyncFlags =
1580
2.06k
              runtime.testAndClearDebuggerAsyncBreakRequest()) {
1581
0
        RUN_DEBUGGER_ASYNC_BREAK(asyncFlags);
1582
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
1583
0
        DISPATCH;
1584
0
      }
1585
2.06k
#endif
1586
1587
      // Subtract 1 from callArgCount as 'this' is considered an argument in the
1588
      // instruction, but not in the frame.
1589
2.06k
      auto newFrame = StackFramePtr::initFrame(
1590
2.06k
          runtime.stackPointer_,
1591
2.06k
          FRAME,
1592
2.06k
          ip,
1593
2.06k
          curCodeBlock,
1594
2.06k
          callArgCount - 1,
1595
2.06k
          O2REG(Call),
1596
2.06k
          HermesValue::fromRaw(callNewTarget));
1597
2.06k
      (void)newFrame;
1598
1599
2.06k
      SLOW_DEBUG(dumpCallArguments(dbgs(), runtime, newFrame));
1600
1601
2.06k
      if (auto *func = dyn_vmcast<JSFunction>(O2REG(Call))) {
1602
1.41k
        assert(!SingleStep && "can't single-step a call");
1603
1604
1.41k
#ifdef HERMES_MEMORY_INSTRUMENTATION
1605
1.41k
        runtime.pushCallStack(curCodeBlock, ip);
1606
1.41k
#endif
1607
1608
1.41k
        CodeBlock *calleeBlock = func->getCodeBlock(runtime);
1609
1.41k
        CAPTURE_IP_ASSIGN(auto res, calleeBlock->lazyCompile(runtime));
1610
1.41k
        if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
1611
0
          goto exception;
1612
0
        }
1613
1.41k
        curCodeBlock = calleeBlock;
1614
1.41k
        CAPTURE_IP_SET();
1615
1.41k
        goto tailCall;
1616
1.41k
      }
1617
657
      CAPTURE_IP(
1618
657
          resPH = Interpreter::handleCallSlowPath(runtime, &O2REG(Call)));
1619
657
      if (LLVM_UNLIKELY(resPH == ExecutionStatus::EXCEPTION)) {
1620
5
        goto exception;
1621
5
      }
1622
652
      O1REG(Call) = std::move(resPH->get());
1623
652
      SLOW_DEBUG(
1624
652
          dbgs() << "native return value r" << (unsigned)ip->iCall.op1 << "="
1625
652
                 << DumpHermesValue(O1REG(Call)) << "\n");
1626
652
      gcScope.flushToSmallCount(KEEP_HANDLES);
1627
652
      ip = nextIP;
1628
3.26k
      DISPATCH;
1629
3.26k
    }
1630
1631
0
      CASE(CallDirect)
1632
0
      CASE(CallDirectLongIndex) {
1633
0
#ifdef HERMES_ENABLE_DEBUGGER
1634
        // Check for an async debugger request.
1635
0
        if (uint8_t asyncFlags =
1636
0
                runtime.testAndClearDebuggerAsyncBreakRequest()) {
1637
0
          RUN_DEBUGGER_ASYNC_BREAK(asyncFlags);
1638
0
          gcScope.flushToSmallCount(KEEP_HANDLES);
1639
0
          DISPATCH;
1640
0
        }
1641
0
#endif
1642
1643
0
        CAPTURE_IP_ASSIGN(
1644
0
            CodeBlock * calleeBlock,
1645
0
            ip->opCode == OpCode::CallDirect
1646
0
                ? curCodeBlock->getRuntimeModule()->getCodeBlockMayAllocate(
1647
0
                      ip->iCallDirect.op3)
1648
0
                : curCodeBlock->getRuntimeModule()->getCodeBlockMayAllocate(
1649
0
                      ip->iCallDirectLongIndex.op3));
1650
1651
0
        auto newFrame = StackFramePtr::initFrame(
1652
0
            runtime.stackPointer_,
1653
0
            FRAME,
1654
0
            ip,
1655
0
            curCodeBlock,
1656
0
            (uint32_t)ip->iCallDirect.op2 - 1,
1657
0
            HermesValue::encodeNativePointer(calleeBlock),
1658
0
            HermesValue::encodeUndefinedValue());
1659
0
        (void)newFrame;
1660
1661
0
        LLVM_DEBUG(dumpCallArguments(dbgs(), runtime, newFrame));
1662
1663
0
        assert(!SingleStep && "can't single-step a call");
1664
1665
0
        CAPTURE_IP_ASSIGN(auto res, calleeBlock->lazyCompile(runtime));
1666
0
        if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
1667
0
          goto exception;
1668
0
        }
1669
0
        curCodeBlock = calleeBlock;
1670
0
        CAPTURE_IP_SET();
1671
0
        goto tailCall;
1672
0
      }
1673
1674
0
      CASE(GetBuiltinClosure) {
1675
0
        uint8_t methodIndex = ip->iCallBuiltin.op2;
1676
0
        Callable *closure = runtime.getBuiltinCallable(methodIndex);
1677
0
        O1REG(GetBuiltinClosure) = HermesValue::encodeObjectValue(closure);
1678
0
        ip = NEXTINST(GetBuiltinClosure);
1679
0
        DISPATCH;
1680
0
      }
1681
1682
105
      CASE(CallBuiltin) {
1683
105
        CAPTURE_IP_ASSIGN(
1684
105
            auto cres,
1685
105
            implCallBuiltin(
1686
105
                runtime, frameRegs, curCodeBlock, ip->iCallBuiltin.op3));
1687
105
        if (LLVM_UNLIKELY(cres == ExecutionStatus::EXCEPTION))
1688
0
          goto exception;
1689
105
        gcScope.flushToSmallCount(KEEP_HANDLES);
1690
105
        ip = NEXTINST(CallBuiltin);
1691
525
        DISPATCH;
1692
525
      }
1693
7
      CASE(CallBuiltinLong) {
1694
7
        CAPTURE_IP_ASSIGN(
1695
7
            auto cres,
1696
7
            implCallBuiltin(
1697
7
                runtime, frameRegs, curCodeBlock, ip->iCallBuiltinLong.op3));
1698
7
        if (LLVM_UNLIKELY(cres == ExecutionStatus::EXCEPTION))
1699
0
          goto exception;
1700
7
        gcScope.flushToSmallCount(KEEP_HANDLES);
1701
7
        ip = NEXTINST(CallBuiltinLong);
1702
35
        DISPATCH;
1703
35
      }
1704
1705
0
      CASE(CompleteGenerator) {
1706
0
        auto *innerFn = vmcast<GeneratorInnerFunction>(
1707
0
            runtime.getCurrentFrame().getCalleeClosureUnsafe());
1708
0
        innerFn->setState(GeneratorInnerFunction::State::Completed);
1709
0
        ip = NEXTINST(CompleteGenerator);
1710
0
        DISPATCH;
1711
0
      }
1712
1713
0
      CASE(SaveGenerator) {
1714
0
        DONT_CAPTURE_IP(
1715
0
            saveGenerator(runtime, frameRegs, IPADD(ip->iSaveGenerator.op1)));
1716
0
        ip = NEXTINST(SaveGenerator);
1717
0
        DISPATCH;
1718
0
      }
1719
0
      CASE(SaveGeneratorLong) {
1720
0
        DONT_CAPTURE_IP(saveGenerator(
1721
0
            runtime, frameRegs, IPADD(ip->iSaveGeneratorLong.op1)));
1722
0
        ip = NEXTINST(SaveGeneratorLong);
1723
0
        DISPATCH;
1724
0
      }
1725
1726
0
      CASE(StartGenerator) {
1727
0
        auto *innerFn = vmcast<GeneratorInnerFunction>(
1728
0
            runtime.getCurrentFrame().getCalleeClosureUnsafe());
1729
0
        if (innerFn->getState() ==
1730
0
            GeneratorInnerFunction::State::SuspendedStart) {
1731
0
          nextIP = NEXTINST(StartGenerator);
1732
0
        } else {
1733
0
          nextIP = innerFn->getNextIP(runtime);
1734
0
          innerFn->restoreStack(runtime);
1735
0
        }
1736
0
        innerFn->setState(GeneratorInnerFunction::State::Executing);
1737
0
        ip = nextIP;
1738
0
        DISPATCH;
1739
0
      }
1740
1741
0
      CASE(ResumeGenerator) {
1742
0
        auto *innerFn = vmcast<GeneratorInnerFunction>(
1743
0
            runtime.getCurrentFrame().getCalleeClosureUnsafe());
1744
0
        O2REG(ResumeGenerator) = HermesValue::encodeBoolValue(
1745
0
            innerFn->getAction() == GeneratorInnerFunction::Action::Return);
1746
        // Write the result last in case it is the same register as O2REG.
1747
0
        O1REG(ResumeGenerator) = innerFn->getResult().unboxToHV(runtime);
1748
0
        innerFn->clearResult(runtime);
1749
0
        if (innerFn->getAction() == GeneratorInnerFunction::Action::Throw) {
1750
0
          runtime.setThrownValue(O1REG(ResumeGenerator));
1751
0
          goto exception;
1752
0
        }
1753
0
        ip = NEXTINST(ResumeGenerator);
1754
0
        DISPATCH;
1755
0
      }
1756
1757
1.61k
      CASE(Ret) {
1758
1.61k
#ifdef HERMES_ENABLE_DEBUGGER
1759
        // Check for an async debugger request, but skip it if we're single
1760
        // stepping. The only case where we'd be single stepping a Ret is if it
1761
        // was replaced with Debugger OpCode and we're coming here from
1762
        // stepFunction(). This does take away a chance to handle AsyncBreak. An
1763
        // AsyncBreak request could be either Explicit or Implicit. The Explicit
1764
        // case is to have the program being executed to pause. There isn't a
1765
        // need to pause at a particular location. Also, since we just came from
1766
        // a breakpoint, handling Explicit AsyncBreak for single step isn't so
1767
        // important. The other possible kind is an Implicit AsyncBreak, which
1768
        // is used for debug clients to interrupt the runtime to execute their
1769
        // own code. Not processing AsyncBreak just means that the Implicit
1770
        // AsyncBreak needs to wait for the next opportunity to interrupt the
1771
        // runtime, which should be fine. There is no contract for when the
1772
        // interrupt should happen.
1773
1.61k
        if (!SingleStep) {
1774
1.61k
          if (uint8_t asyncFlags =
1775
1.61k
                  runtime.testAndClearDebuggerAsyncBreakRequest()) {
1776
0
            RUN_DEBUGGER_ASYNC_BREAK(asyncFlags);
1777
0
            gcScope.flushToSmallCount(KEEP_HANDLES);
1778
0
            DISPATCH;
1779
0
          }
1780
1.61k
        }
1781
1.61k
#endif
1782
1783
1.61k
        PROFILER_EXIT_FUNCTION(curCodeBlock);
1784
1785
1.61k
#ifdef HERMES_MEMORY_INSTRUMENTATION
1786
1.61k
        runtime.popCallStack();
1787
1.61k
#endif
1788
1789
        // Store the return value.
1790
1.61k
        res = O1REG(Ret);
1791
1792
1.61k
        ip = FRAME.getSavedIP();
1793
1.61k
        curCodeBlock = FRAME.getSavedCodeBlock();
1794
1795
1.61k
        frameRegs =
1796
1.61k
            &runtime.restoreStackAndPreviousFrame(FRAME).getFirstLocalRef();
1797
1798
1.61k
        SLOW_DEBUG(
1799
1.61k
            dbgs() << "function exit: restored stackLevel="
1800
1.61k
                   << runtime.getStackLevel() << "\n");
1801
1802
        // Are we returning to native code?
1803
1.61k
        if (!curCodeBlock) {
1804
201
          SLOW_DEBUG(dbgs() << "function exit: returning to native code\n");
1805
201
          return res;
1806
201
        }
1807
1808
1.41k
        INIT_STATE_FOR_CODEBLOCK(curCodeBlock);
1809
1.41k
        O1REG(Call) = res.getValue();
1810
1811
1.41k
#ifdef HERMES_ENABLE_DEBUGGER
1812
        // Only do the more expensive check for breakpoint location (in
1813
        // getRealOpCode) if there are breakpoints installed in the function
1814
        // we're returning into.
1815
1.41k
        if (LLVM_UNLIKELY(curCodeBlock->getNumInstalledBreakpoints() > 0)) {
1816
0
          ip = IPADD(
1817
0
              inst::getInstSize(
1818
0
                  runtime.debugger_.getRealOpCode(curCodeBlock, CUROFFSET)));
1819
1.41k
        } else {
1820
          // No breakpoints in the function being returned to, just use
1821
          // nextInstCall().
1822
1.41k
          ip = nextInstCall(ip);
1823
1.41k
        }
1824
#else
1825
        ip = nextInstCall(ip);
1826
#endif
1827
1828
7.05k
        DISPATCH;
1829
7.05k
      }
1830
1831
0
      CASE(Catch) {
1832
0
        assert(!runtime.thrownValue_.isEmpty() && "Invalid thrown value");
1833
0
        assert(
1834
0
            !isUncatchableError(runtime.thrownValue_) &&
1835
0
            "Uncatchable thrown value was caught");
1836
0
        O1REG(Catch) = runtime.thrownValue_;
1837
0
        runtime.clearThrownValue();
1838
0
#ifdef HERMES_ENABLE_DEBUGGER
1839
        // Signal to the debugger that we're done unwinding an exception,
1840
        // and we can resume normal debugging flow.
1841
0
        runtime.debugger_.finishedUnwindingException();
1842
0
#endif
1843
0
        ip = NEXTINST(Catch);
1844
0
        DISPATCH;
1845
0
      }
1846
1847
0
      CASE(Throw) {
1848
0
        runtime.thrownValue_ = O1REG(Throw);
1849
0
        SLOW_DEBUG(
1850
0
            dbgs() << "Exception thrown: "
1851
0
                   << DumpHermesValue(runtime.thrownValue_) << "\n");
1852
0
        goto exception;
1853
0
      }
1854
1855
0
      CASE(ThrowIfEmpty) {
1856
0
        if (LLVM_UNLIKELY(O2REG(ThrowIfEmpty).isEmpty())) {
1857
0
          SLOW_DEBUG(dbgs() << "Throwing ReferenceError for empty variable");
1858
0
          CAPTURE_IP(runtime.raiseReferenceError(
1859
0
              "accessing an uninitialized variable"));
1860
0
          goto exception;
1861
0
        }
1862
0
        O1REG(ThrowIfEmpty) = O2REG(ThrowIfEmpty);
1863
0
        ip = NEXTINST(ThrowIfEmpty);
1864
0
        DISPATCH;
1865
0
      }
1866
1867
0
      CASE(Debugger) {
1868
0
        SLOW_DEBUG(dbgs() << "debugger statement executed\n");
1869
0
#ifdef HERMES_ENABLE_DEBUGGER
1870
0
        {
1871
0
          if (!runtime.debugger_.isDebugging()) {
1872
            // Only run the debugger if we're not already debugging.
1873
            // Don't want to call it again and mess with its state.
1874
0
            CAPTURE_IP_ASSIGN(
1875
0
                auto res,
1876
0
                runDebuggerUpdatingState(
1877
0
                    Debugger::RunReason::Opcode,
1878
0
                    runtime,
1879
0
                    curCodeBlock,
1880
0
                    ip,
1881
0
                    frameRegs));
1882
0
            if (res == ExecutionStatus::EXCEPTION) {
1883
              // If one of the internal steps threw,
1884
              // then handle that here by jumping to where we're supposed to go.
1885
              // If we're in mid-step, the breakpoint at the catch point
1886
              // will have been set by the debugger.
1887
              // We don't want to execute this instruction because it's already
1888
              // thrown.
1889
0
              goto exception;
1890
0
            }
1891
0
          }
1892
0
          InterpreterState newState{curCodeBlock, (uint32_t)CUROFFSET};
1893
0
          ExecutionStatus status =
1894
0
              runtime.debugger_.processInstUnderDebuggerOpCode(newState);
1895
0
          if (status == ExecutionStatus::EXCEPTION) {
1896
0
            goto exception;
1897
0
          }
1898
1899
0
          if (newState.codeBlock != curCodeBlock ||
1900
0
              newState.offset != (uint32_t)CUROFFSET) {
1901
0
            ip = newState.codeBlock->getOffsetPtr(newState.offset);
1902
1903
0
            if (newState.codeBlock != curCodeBlock) {
1904
0
              curCodeBlock = newState.codeBlock;
1905
0
              INIT_STATE_FOR_CODEBLOCK(curCodeBlock);
1906
              // Single-stepping should handle call stack management for us.
1907
0
              frameRegs = &runtime.getCurrentFrame().getFirstLocalRef();
1908
0
            }
1909
0
          }
1910
0
          gcScope.flushToSmallCount(KEEP_HANDLES);
1911
0
        }
1912
0
        DISPATCH;
1913
#else
1914
        ip = NEXTINST(Debugger);
1915
        DISPATCH;
1916
#endif
1917
0
      }
1918
1919
511k
      CASE(AsyncBreakCheck) {
1920
511k
        if (LLVM_UNLIKELY(runtime.hasAsyncBreak())) {
1921
0
#ifdef HERMES_ENABLE_DEBUGGER
1922
0
          if (uint8_t asyncFlags =
1923
0
                  runtime.testAndClearDebuggerAsyncBreakRequest()) {
1924
0
            RUN_DEBUGGER_ASYNC_BREAK(asyncFlags);
1925
0
          }
1926
0
#endif
1927
0
          if (runtime.testAndClearTimeoutAsyncBreakRequest()) {
1928
0
            CAPTURE_IP_ASSIGN(auto nRes, runtime.notifyTimeout());
1929
0
            if (nRes == ExecutionStatus::EXCEPTION) {
1930
0
              goto exception;
1931
0
            }
1932
0
          }
1933
0
        }
1934
511k
        gcScope.flushToSmallCount(KEEP_HANDLES);
1935
1936
511k
        ip = NEXTINST(AsyncBreakCheck);
1937
2.55M
        DISPATCH;
1938
2.55M
      }
1939
1940
0
      CASE(ProfilePoint) {
1941
#ifdef HERMESVM_PROFILER_BB
1942
        auto pointIndex = ip->iProfilePoint.op1;
1943
        SLOW_DEBUG(llvh::dbgs() << "ProfilePoint: " << pointIndex << "\n");
1944
        CAPTURE_IP(runtime.getBasicBlockExecutionInfo().executeBlock(
1945
            curCodeBlock, pointIndex));
1946
#endif
1947
0
        ip = NEXTINST(ProfilePoint);
1948
0
        DISPATCH;
1949
0
      }
1950
1951
      // Use a macro here to avoid clang-format issues with a literal default:
1952
      // label.
1953
0
      DEFAULT_CASE
1954
0
      CASE(Unreachable) {
1955
0
        hermes_fatal("Unreachable instruction encountered");
1956
        // The fatal call doesn't return, no need to set the IP differently and
1957
        // dispatch.
1958
0
      }
1959
1960
3.46k
      CASE(CreateClosure) {
1961
3.46k
        idVal = ip->iCreateClosure.op3;
1962
3.46k
        nextIP = NEXTINST(CreateClosure);
1963
3.46k
        goto createClosure;
1964
0
      }
1965
0
      CASE(CreateClosureLongIndex) {
1966
0
        idVal = ip->iCreateClosureLongIndex.op3;
1967
0
        nextIP = NEXTINST(CreateClosureLongIndex);
1968
0
        goto createClosure;
1969
0
      }
1970
3.46k
    createClosure: {
1971
3.46k
      auto *runtimeModule = curCodeBlock->getRuntimeModule();
1972
3.46k
      CAPTURE_IP(
1973
3.46k
          O1REG(CreateClosure) =
1974
3.46k
              JSFunction::create(
1975
3.46k
                  runtime,
1976
3.46k
                  runtimeModule->getDomain(runtime),
1977
3.46k
                  Handle<JSObject>::vmcast(&runtime.functionPrototype),
1978
3.46k
                  Handle<Environment>::vmcast(&O2REG(CreateClosure)),
1979
3.46k
                  runtimeModule->getCodeBlockMayAllocate(idVal))
1980
3.46k
                  .getHermesValue());
1981
3.46k
      gcScope.flushToSmallCount(KEEP_HANDLES);
1982
3.46k
      ip = nextIP;
1983
17.3k
      DISPATCH;
1984
17.3k
    }
1985
1986
0
      CASE(CreateAsyncClosure) {
1987
0
        idVal = ip->iCreateAsyncClosure.op3;
1988
0
        nextIP = NEXTINST(CreateAsyncClosure);
1989
0
        goto createAsyncClosure;
1990
17.3k
      }
1991
0
      CASE(CreateAsyncClosureLongIndex) {
1992
0
        idVal = ip->iCreateAsyncClosureLongIndex.op3;
1993
0
        nextIP = NEXTINST(CreateAsyncClosureLongIndex);
1994
0
        goto createAsyncClosure;
1995
17.3k
      }
1996
0
    createAsyncClosure: {
1997
0
      auto *runtimeModule = curCodeBlock->getRuntimeModule();
1998
0
      CAPTURE_IP_ASSIGN(
1999
0
          O1REG(CreateAsyncClosure),
2000
0
          JSAsyncFunction::create(
2001
0
              runtime,
2002
0
              runtimeModule->getDomain(runtime),
2003
0
              Handle<JSObject>::vmcast(&runtime.asyncFunctionPrototype),
2004
0
              Handle<Environment>::vmcast(&O2REG(CreateAsyncClosure)),
2005
0
              runtimeModule->getCodeBlockMayAllocate(idVal))
2006
0
              .getHermesValue());
2007
0
      gcScope.flushToSmallCount(KEEP_HANDLES);
2008
0
      ip = nextIP;
2009
0
      DISPATCH;
2010
0
    }
2011
2012
0
      CASE(CreateGeneratorClosure) {
2013
0
        idVal = ip->iCreateGeneratorClosure.op3;
2014
0
        nextIP = NEXTINST(CreateGeneratorClosure);
2015
0
        goto createGeneratorClosure;
2016
0
      }
2017
0
      CASE(CreateGeneratorClosureLongIndex) {
2018
0
        idVal = ip->iCreateGeneratorClosureLongIndex.op3;
2019
0
        nextIP = NEXTINST(CreateGeneratorClosureLongIndex);
2020
0
        goto createGeneratorClosure;
2021
0
      }
2022
0
    createGeneratorClosure: {
2023
0
      auto *runtimeModule = curCodeBlock->getRuntimeModule();
2024
0
      CAPTURE_IP_ASSIGN(
2025
0
          O1REG(CreateGeneratorClosure),
2026
0
          JSGeneratorFunction::create(
2027
0
              runtime,
2028
0
              runtimeModule->getDomain(runtime),
2029
0
              Handle<JSObject>::vmcast(&runtime.generatorFunctionPrototype),
2030
0
              Handle<Environment>::vmcast(&O2REG(CreateGeneratorClosure)),
2031
0
              runtimeModule->getCodeBlockMayAllocate(idVal))
2032
0
              .getHermesValue());
2033
0
      gcScope.flushToSmallCount(KEEP_HANDLES);
2034
0
      ip = nextIP;
2035
0
      DISPATCH;
2036
0
    }
2037
2038
0
      CASE(CreateGenerator) {
2039
0
        CAPTURE_IP_ASSIGN(
2040
0
            auto res,
2041
0
            createGenerator_RJS(
2042
0
                runtime,
2043
0
                curCodeBlock->getRuntimeModule(),
2044
0
                ip->iCreateGenerator.op3,
2045
0
                Handle<Environment>::vmcast(&O2REG(CreateGenerator)),
2046
0
                FRAME.getNativeArgs()));
2047
0
        if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
2048
0
          goto exception;
2049
0
        }
2050
0
        O1REG(CreateGenerator) = res->getHermesValue();
2051
0
        res->invalidate();
2052
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2053
0
        ip = NEXTINST(CreateGenerator);
2054
0
        DISPATCH;
2055
0
      }
2056
0
      CASE(CreateGeneratorLongIndex) {
2057
0
        CAPTURE_IP_ASSIGN(
2058
0
            auto res,
2059
0
            createGenerator_RJS(
2060
0
                runtime,
2061
0
                curCodeBlock->getRuntimeModule(),
2062
0
                ip->iCreateGeneratorLongIndex.op3,
2063
0
                Handle<Environment>::vmcast(&O2REG(CreateGeneratorLongIndex)),
2064
0
                FRAME.getNativeArgs()));
2065
0
        if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
2066
0
          goto exception;
2067
0
        }
2068
0
        O1REG(CreateGeneratorLongIndex) = res->getHermesValue();
2069
0
        res->invalidate();
2070
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2071
0
        ip = NEXTINST(CreateGeneratorLongIndex);
2072
0
        DISPATCH;
2073
0
      }
2074
2075
1.22k
      CASE(GetEnvironment) {
2076
        // The currently executing function must exist, so get the environment.
2077
1.22k
        Environment *curEnv =
2078
1.22k
            FRAME.getCalleeClosureUnsafe()->getEnvironment(runtime);
2079
1.22k
        for (unsigned level = ip->iGetEnvironment.op2; level; --level) {
2080
0
          assert(curEnv && "invalid environment relative level");
2081
0
          curEnv = curEnv->getParentEnvironment(runtime);
2082
0
        }
2083
1.22k
        O1REG(GetEnvironment) = HermesValue::encodeObjectValue(curEnv);
2084
1.22k
        ip = NEXTINST(GetEnvironment);
2085
6.11k
        DISPATCH;
2086
6.11k
      }
2087
2088
0
      CASE(CreateInnerEnvironment) {
2089
0
        CAPTURE_IP(
2090
0
            O1REG(CreateInnerEnvironment) = Environment::create(
2091
0
                runtime,
2092
0
                Handle<Environment>::vmcast(&O2REG(CreateInnerEnvironment)),
2093
0
                ip->iCreateInnerEnvironment.op3));
2094
0
        ip = NEXTINST(CreateInnerEnvironment);
2095
0
        DISPATCH;
2096
0
      }
2097
2098
513
      CASE(CreateEnvironment) {
2099
513
        tmpHandle = HermesValue::encodeObjectValueUnsafe(
2100
513
            FRAME.getCalleeClosureUnsafe()->getEnvironment(runtime));
2101
2102
513
        CAPTURE_IP(
2103
513
            O1REG(CreateEnvironment) = Environment::create(
2104
513
                runtime,
2105
513
                Handle<Environment>::vmcast_or_null(tmpHandle),
2106
513
                curCodeBlock->getEnvironmentSize()));
2107
2108
513
        tmpHandle = HermesValue::encodeUndefinedValue();
2109
513
        ip = NEXTINST(CreateEnvironment);
2110
2.56k
        DISPATCH;
2111
2.56k
      }
2112
2113
3.31k
      CASE(StoreToEnvironment) {
2114
3.31k
        vmcast<Environment>(O1REG(StoreToEnvironment))
2115
3.31k
            ->slot(ip->iStoreToEnvironment.op2)
2116
3.31k
            .set(O3REG(StoreToEnvironment), runtime.getHeap());
2117
3.31k
        ip = NEXTINST(StoreToEnvironment);
2118
16.5k
        DISPATCH;
2119
16.5k
      }
2120
0
      CASE(StoreToEnvironmentL) {
2121
0
        vmcast<Environment>(O1REG(StoreToEnvironmentL))
2122
0
            ->slot(ip->iStoreToEnvironmentL.op2)
2123
0
            .set(O3REG(StoreToEnvironmentL), runtime.getHeap());
2124
0
        ip = NEXTINST(StoreToEnvironmentL);
2125
0
        DISPATCH;
2126
0
      }
2127
2128
191
      CASE(StoreNPToEnvironment) {
2129
191
        vmcast<Environment>(O1REG(StoreNPToEnvironment))
2130
191
            ->slot(ip->iStoreNPToEnvironment.op2)
2131
191
            .setNonPtr(O3REG(StoreNPToEnvironment), runtime.getHeap());
2132
191
        ip = NEXTINST(StoreNPToEnvironment);
2133
955
        DISPATCH;
2134
955
      }
2135
0
      CASE(StoreNPToEnvironmentL) {
2136
0
        vmcast<Environment>(O1REG(StoreNPToEnvironmentL))
2137
0
            ->slot(ip->iStoreNPToEnvironmentL.op2)
2138
0
            .setNonPtr(O3REG(StoreNPToEnvironmentL), runtime.getHeap());
2139
0
        ip = NEXTINST(StoreNPToEnvironmentL);
2140
0
        DISPATCH;
2141
0
      }
2142
2143
1.22k
      CASE(LoadFromEnvironment) {
2144
1.22k
        O1REG(LoadFromEnvironment) =
2145
1.22k
            vmcast<Environment>(O2REG(LoadFromEnvironment))
2146
1.22k
                ->slot(ip->iLoadFromEnvironment.op3);
2147
1.22k
        ip = NEXTINST(LoadFromEnvironment);
2148
6.11k
        DISPATCH;
2149
6.11k
      }
2150
2151
0
      CASE(LoadFromEnvironmentL) {
2152
0
        O1REG(LoadFromEnvironmentL) =
2153
0
            vmcast<Environment>(O2REG(LoadFromEnvironmentL))
2154
0
                ->slot(ip->iLoadFromEnvironmentL.op3);
2155
0
        ip = NEXTINST(LoadFromEnvironmentL);
2156
0
        DISPATCH;
2157
0
      }
2158
2159
512k
      CASE(GetGlobalObject) {
2160
512k
        O1REG(GetGlobalObject) = runtime.global_;
2161
512k
        ip = NEXTINST(GetGlobalObject);
2162
2.56M
        DISPATCH;
2163
2.56M
      }
2164
2165
9
      CASE(GetNewTarget) {
2166
9
        O1REG(GetNewTarget) = FRAME.getNewTargetRef();
2167
9
        ip = NEXTINST(GetNewTarget);
2168
45
        DISPATCH;
2169
45
      }
2170
2171
0
      CASE(DeclareGlobalVar) {
2172
0
        CAPTURE_IP_ASSIGN(
2173
0
            auto res, declareGlobalVarImpl(runtime, curCodeBlock, ip));
2174
0
        if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
2175
0
          goto exception;
2176
0
        }
2177
0
        ip = NEXTINST(DeclareGlobalVar);
2178
0
        DISPATCH;
2179
0
      }
2180
2181
0
      CASE(ThrowIfHasRestrictedGlobalProperty) {
2182
0
        CAPTURE_IP_ASSIGN(
2183
0
            auto res,
2184
0
            throwIfHasRestrictedGlobalPropertyImpl(runtime, curCodeBlock, ip));
2185
0
        if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
2186
0
          goto exception;
2187
0
        }
2188
0
        ip = NEXTINST(ThrowIfHasRestrictedGlobalProperty);
2189
0
        DISPATCH;
2190
0
      }
2191
2192
0
      CASE(TryGetByIdLong) {
2193
0
        tryProp = true;
2194
0
        idVal = ip->iTryGetByIdLong.op4;
2195
0
        nextIP = NEXTINST(TryGetByIdLong);
2196
0
        goto getById;
2197
0
      }
2198
0
      CASE(GetByIdLong) {
2199
0
        tryProp = false;
2200
0
        idVal = ip->iGetByIdLong.op4;
2201
0
        nextIP = NEXTINST(GetByIdLong);
2202
0
        goto getById;
2203
0
      }
2204
2.25k
      CASE(GetByIdShort) {
2205
2.25k
        tryProp = false;
2206
2.25k
        idVal = ip->iGetByIdShort.op4;
2207
2.25k
        nextIP = NEXTINST(GetByIdShort);
2208
2.25k
        goto getById;
2209
0
      }
2210
1.05k
      CASE(TryGetById) {
2211
1.05k
        tryProp = true;
2212
1.05k
        idVal = ip->iTryGetById.op4;
2213
1.05k
        nextIP = NEXTINST(TryGetById);
2214
1.05k
        goto getById;
2215
0
      }
2216
0
      CASE(GetById) {
2217
0
        tryProp = false;
2218
0
        idVal = ip->iGetById.op4;
2219
0
        nextIP = NEXTINST(GetById);
2220
0
      }
2221
3.31k
    getById: {
2222
3.31k
      ++NumGetById;
2223
      // NOTE: it is safe to use OnREG(GetById) here because all instructions
2224
      // have the same layout: opcode, registers, non-register operands, i.e.
2225
      // they only differ in the width of the last "identifier" field.
2226
3.31k
      if (LLVM_LIKELY(O2REG(GetById).isObject())) {
2227
3.31k
        auto *obj = vmcast<JSObject>(O2REG(GetById));
2228
3.31k
        auto cacheIdx = ip->iGetById.op3;
2229
3.31k
        auto *cacheEntry = curCodeBlock->getReadCacheEntry(cacheIdx);
2230
2231
#ifdef HERMESVM_PROFILER_BB
2232
        {
2233
          HERMES_SLOW_ASSERT(
2234
              gcScope.getHandleCountDbg() == KEEP_HANDLES &&
2235
              "unaccounted handles were created");
2236
          auto objHandle = runtime.makeHandle(obj);
2237
          auto cacheHCPtr = vmcast_or_null<HiddenClass>(static_cast<GCCell *>(
2238
              cacheEntry->clazz.get(runtime, runtime.getHeap())));
2239
          CAPTURE_IP(runtime.recordHiddenClass(
2240
              curCodeBlock, ip, ID(idVal), obj->getClass(runtime), cacheHCPtr));
2241
          // obj may be moved by GC due to recordHiddenClass
2242
          obj = objHandle.get();
2243
        }
2244
        gcScope.flushToSmallCount(KEEP_HANDLES);
2245
#endif
2246
3.31k
        CompressedPointer clazzPtr{obj->getClassGCPtr()};
2247
3.31k
#ifndef NDEBUG
2248
3.31k
        if (vmcast<HiddenClass>(clazzPtr.getNonNull(runtime))->isDictionary())
2249
119
          ++NumGetByIdDict;
2250
#else
2251
        (void)NumGetByIdDict;
2252
#endif
2253
2254
        // If we have a cache hit, reuse the cached offset and immediately
2255
        // return the property.
2256
3.31k
        if (LLVM_LIKELY(cacheEntry->clazz == clazzPtr)) {
2257
1.20k
          ++NumGetByIdCacheHits;
2258
1.20k
          CAPTURE_IP(
2259
1.20k
              O1REG(GetById) =
2260
1.20k
                  JSObject::getNamedSlotValueUnsafe<PropStorage::Inline::Yes>(
2261
1.20k
                      obj, runtime, cacheEntry->slot)
2262
1.20k
                      .unboxToHV(runtime));
2263
1.20k
          ip = nextIP;
2264
6.02k
          DISPATCH;
2265
6.02k
        }
2266
3.31k
        auto id = ID(idVal);
2267
3.31k
        NamedPropertyDescriptor desc;
2268
3.31k
        CAPTURE_IP_ASSIGN(
2269
3.31k
            OptValue<bool> fastPathResult,
2270
3.31k
            JSObject::tryGetOwnNamedDescriptorFast(obj, runtime, id, desc));
2271
3.31k
        if (LLVM_LIKELY(
2272
3.31k
                fastPathResult.hasValue() && fastPathResult.getValue()) &&
2273
1.89k
            !desc.flags.accessor) {
2274
1.89k
          ++NumGetByIdFastPaths;
2275
2276
          // cacheIdx == 0 indicates no caching so don't update the cache in
2277
          // those cases.
2278
1.89k
          HiddenClass *clazz =
2279
1.89k
              vmcast<HiddenClass>(clazzPtr.getNonNull(runtime));
2280
1.89k
          if (LLVM_LIKELY(!clazz->isDictionaryNoCache()) &&
2281
1.89k
              LLVM_LIKELY(cacheIdx != hbc::PROPERTY_CACHING_DISABLED)) {
2282
1.89k
#ifdef HERMES_SLOW_DEBUG
2283
1.89k
            if (cacheEntry->clazz && cacheEntry->clazz != clazzPtr)
2284
376
              ++NumGetByIdCacheEvicts;
2285
#else
2286
            (void)NumGetByIdCacheEvicts;
2287
#endif
2288
            // Cache the class, id and property slot.
2289
1.89k
            cacheEntry->clazz = clazzPtr;
2290
1.89k
            cacheEntry->slot = desc.slot;
2291
1.89k
          }
2292
2293
1.89k
          assert(
2294
1.89k
              !obj->isProxyObject() &&
2295
1.89k
              "tryGetOwnNamedDescriptorFast returned true on Proxy");
2296
1.89k
          CAPTURE_IP(
2297
1.89k
              O1REG(GetById) =
2298
1.89k
                  JSObject::getNamedSlotValueUnsafe(obj, runtime, desc)
2299
1.89k
                      .unboxToHV(runtime));
2300
1.89k
          ip = nextIP;
2301
9.48k
          DISPATCH;
2302
9.48k
        }
2303
2304
        // The cache may also be populated via the prototype of the object.
2305
        // This value is only reliable if the fast path was a definite
2306
        // not-found.
2307
3.31k
        if (fastPathResult.hasValue() && !fastPathResult.getValue() &&
2308
27
            LLVM_LIKELY(!obj->isProxyObject())) {
2309
27
          CAPTURE_IP_ASSIGN(JSObject * parent, obj->getParent(runtime));
2310
          // TODO: This isLazy check is because a lazy object is reported as
2311
          // having no properties and therefore cannot contain the property.
2312
          // This check does not belong here, it should be merged into
2313
          // tryGetOwnNamedDescriptorFast().
2314
27
          if (parent && cacheEntry->clazz == parent->getClassGCPtr() &&
2315
0
              LLVM_LIKELY(!obj->isLazy())) {
2316
0
            ++NumGetByIdProtoHits;
2317
            // We've already checked that this isn't a Proxy.
2318
0
            CAPTURE_IP(
2319
0
                O1REG(GetById) = JSObject::getNamedSlotValueUnsafe(
2320
0
                                     parent, runtime, cacheEntry->slot)
2321
0
                                     .unboxToHV(runtime));
2322
0
            ip = nextIP;
2323
0
            DISPATCH;
2324
0
          }
2325
27
        }
2326
2327
3.31k
#ifdef HERMES_SLOW_DEBUG
2328
        // Call to getNamedDescriptorUnsafe is safe because `id` is kept alive
2329
        // by the IdentifierTable.
2330
3.31k
        CAPTURE_IP_ASSIGN(
2331
3.31k
            JSObject * propObj,
2332
3.31k
            JSObject::getNamedDescriptorUnsafe(
2333
3.31k
                Handle<JSObject>::vmcast(&O2REG(GetById)), runtime, id, desc));
2334
3.31k
        if (propObj) {
2335
188
          if (desc.flags.accessor)
2336
0
            ++NumGetByIdAccessor;
2337
188
          else if (propObj != vmcast<JSObject>(O2REG(GetById)))
2338
94
            ++NumGetByIdProto;
2339
3.12k
        } else {
2340
3.12k
          ++NumGetByIdNotFound;
2341
3.12k
        }
2342
#else
2343
        (void)NumGetByIdAccessor;
2344
        (void)NumGetByIdProto;
2345
        (void)NumGetByIdNotFound;
2346
#endif
2347
3.31k
#ifdef HERMES_SLOW_DEBUG
2348
3.31k
        auto *savedClass = cacheIdx != hbc::PROPERTY_CACHING_DISABLED
2349
3.31k
            ? cacheEntry->clazz.get(runtime, runtime.getHeap())
2350
3.31k
            : nullptr;
2351
3.31k
#endif
2352
3.31k
        ++NumGetByIdSlow;
2353
3.31k
        CAPTURE_IP(
2354
3.31k
            resPH = JSObject::getNamed_RJS(
2355
3.31k
                Handle<JSObject>::vmcast(&O2REG(GetById)),
2356
3.31k
                runtime,
2357
3.31k
                id,
2358
3.31k
                !tryProp ? defaultPropOpFlags
2359
3.31k
                         : defaultPropOpFlags.plusMustExist(),
2360
3.31k
                cacheIdx != hbc::PROPERTY_CACHING_DISABLED ? cacheEntry
2361
3.31k
                                                           : nullptr));
2362
3.31k
        if (LLVM_UNLIKELY(resPH == ExecutionStatus::EXCEPTION)) {
2363
25
          goto exception;
2364
25
        }
2365
3.29k
#ifdef HERMES_SLOW_DEBUG
2366
3.29k
        if (cacheIdx != hbc::PROPERTY_CACHING_DISABLED && savedClass &&
2367
0
            cacheEntry->clazz.get(runtime, runtime.getHeap()) != savedClass) {
2368
0
          ++NumGetByIdCacheEvicts;
2369
0
        }
2370
3.29k
#endif
2371
3.29k
      } else {
2372
0
        ++NumGetByIdTransient;
2373
0
        assert(!tryProp && "TryGetById can only be used on the global object");
2374
        /* Slow path. */
2375
0
        CAPTURE_IP(
2376
0
            resPH = Interpreter::getByIdTransient_RJS(
2377
0
                runtime, Handle<>(&O2REG(GetById)), ID(idVal)));
2378
0
        if (LLVM_UNLIKELY(resPH == ExecutionStatus::EXCEPTION)) {
2379
0
          goto exception;
2380
0
        }
2381
0
      }
2382
3.29k
      O1REG(GetById) = resPH->get();
2383
3.29k
      gcScope.flushToSmallCount(KEEP_HANDLES);
2384
3.29k
      ip = nextIP;
2385
3.29k
      DISPATCH;
2386
950
    }
2387
2388
0
      CASE(TryPutByIdLong) {
2389
0
        tryProp = true;
2390
0
        idVal = ip->iTryPutByIdLong.op4;
2391
0
        nextIP = NEXTINST(TryPutByIdLong);
2392
0
        goto putById;
2393
950
      }
2394
0
      CASE(PutByIdLong) {
2395
0
        tryProp = false;
2396
0
        idVal = ip->iPutByIdLong.op4;
2397
0
        nextIP = NEXTINST(PutByIdLong);
2398
0
        goto putById;
2399
950
      }
2400
0
      CASE(TryPutById) {
2401
0
        tryProp = true;
2402
0
        idVal = ip->iTryPutById.op4;
2403
0
        nextIP = NEXTINST(TryPutById);
2404
0
        goto putById;
2405
950
      }
2406
516k
      CASE(PutById) {
2407
516k
        tryProp = false;
2408
516k
        idVal = ip->iPutById.op4;
2409
516k
        nextIP = NEXTINST(PutById);
2410
516k
      }
2411
516k
    putById: {
2412
516k
      ++NumPutById;
2413
516k
      if (LLVM_LIKELY(O1REG(PutById).isObject())) {
2414
516k
        CAPTURE_IP_ASSIGN(
2415
516k
            SmallHermesValue shv,
2416
516k
            SmallHermesValue::encodeHermesValue(O2REG(PutById), runtime));
2417
516k
        auto *obj = vmcast<JSObject>(O1REG(PutById));
2418
516k
        auto cacheIdx = ip->iPutById.op3;
2419
516k
        auto *cacheEntry = curCodeBlock->getWriteCacheEntry(cacheIdx);
2420
2421
#ifdef HERMESVM_PROFILER_BB
2422
        {
2423
          HERMES_SLOW_ASSERT(
2424
              gcScope.getHandleCountDbg() == KEEP_HANDLES &&
2425
              "unaccounted handles were created");
2426
          auto shvHandle = runtime.makeHandle(shv.toHV(runtime));
2427
          auto objHandle = runtime.makeHandle(obj);
2428
          auto cacheHCPtr = vmcast_or_null<HiddenClass>(static_cast<GCCell *>(
2429
              cacheEntry->clazz.get(runtime, runtime.getHeap())));
2430
          CAPTURE_IP(runtime.recordHiddenClass(
2431
              curCodeBlock, ip, ID(idVal), obj->getClass(runtime), cacheHCPtr));
2432
          // shv/obj may be invalidated by recordHiddenClass
2433
          if (shv.isPointer())
2434
            shv.unsafeUpdatePointer(
2435
                static_cast<GCCell *>(shvHandle->getPointer()), runtime);
2436
          obj = objHandle.get();
2437
        }
2438
        gcScope.flushToSmallCount(KEEP_HANDLES);
2439
#endif
2440
516k
        CompressedPointer clazzPtr{obj->getClassGCPtr()};
2441
        // If we have a cache hit, reuse the cached offset and immediately
2442
        // return the property.
2443
516k
        if (LLVM_LIKELY(cacheEntry->clazz == clazzPtr)) {
2444
940
          ++NumPutByIdCacheHits;
2445
940
          CAPTURE_IP(
2446
940
              JSObject::setNamedSlotValueUnsafe<PropStorage::Inline::Yes>(
2447
940
                  obj, runtime, cacheEntry->slot, shv));
2448
940
          ip = nextIP;
2449
4.70k
          DISPATCH;
2450
4.70k
        }
2451
516k
        auto id = ID(idVal);
2452
516k
        NamedPropertyDescriptor desc;
2453
516k
        CAPTURE_IP_ASSIGN(
2454
516k
            OptValue<bool> hasOwnProp,
2455
516k
            JSObject::tryGetOwnNamedDescriptorFast(obj, runtime, id, desc));
2456
516k
        if (LLVM_LIKELY(hasOwnProp.hasValue() && hasOwnProp.getValue()) &&
2457
511k
            !desc.flags.accessor && desc.flags.writable &&
2458
511k
            !desc.flags.internalSetter) {
2459
511k
          ++NumPutByIdFastPaths;
2460
2461
          // cacheIdx == 0 indicates no caching so don't update the cache in
2462
          // those cases.
2463
511k
          HiddenClass *clazz =
2464
511k
              vmcast<HiddenClass>(clazzPtr.getNonNull(runtime));
2465
511k
          if (LLVM_LIKELY(!clazz->isDictionary()) &&
2466
188
              LLVM_LIKELY(cacheIdx != hbc::PROPERTY_CACHING_DISABLED)) {
2467
188
#ifdef HERMES_SLOW_DEBUG
2468
188
            if (cacheEntry->clazz && cacheEntry->clazz != clazzPtr)
2469
0
              ++NumPutByIdCacheEvicts;
2470
#else
2471
            (void)NumPutByIdCacheEvicts;
2472
#endif
2473
            // Cache the class and property slot.
2474
188
            cacheEntry->clazz = clazzPtr;
2475
188
            cacheEntry->slot = desc.slot;
2476
188
          }
2477
2478
          // This must be valid because an own property was already found.
2479
511k
          CAPTURE_IP(
2480
511k
              JSObject::setNamedSlotValueUnsafe(obj, runtime, desc.slot, shv));
2481
511k
          ip = nextIP;
2482
2.55M
          DISPATCH;
2483
2.55M
        }
2484
2485
516k
        CAPTURE_IP_ASSIGN(
2486
516k
            auto putRes,
2487
516k
            JSObject::putNamed_RJS(
2488
516k
                Handle<JSObject>::vmcast(&O1REG(PutById)),
2489
516k
                runtime,
2490
516k
                id,
2491
516k
                Handle<>(&O2REG(PutById)),
2492
516k
                !tryProp ? defaultPropOpFlags
2493
516k
                         : defaultPropOpFlags.plusMustExist()));
2494
516k
        if (LLVM_UNLIKELY(putRes == ExecutionStatus::EXCEPTION)) {
2495
0
          goto exception;
2496
0
        }
2497
516k
      } else {
2498
0
        ++NumPutByIdTransient;
2499
0
        assert(!tryProp && "TryPutById can only be used on the global object");
2500
0
        CAPTURE_IP_ASSIGN(
2501
0
            auto retStatus,
2502
0
            Interpreter::putByIdTransient_RJS(
2503
0
                runtime,
2504
0
                Handle<>(&O1REG(PutById)),
2505
0
                ID(idVal),
2506
0
                Handle<>(&O2REG(PutById)),
2507
0
                strictMode));
2508
0
        if (retStatus == ExecutionStatus::EXCEPTION) {
2509
0
          goto exception;
2510
0
        }
2511
0
      }
2512
516k
      gcScope.flushToSmallCount(KEEP_HANDLES);
2513
516k
      ip = nextIP;
2514
516k
      DISPATCH;
2515
17.9k
    }
2516
2517
0
      CASE(GetByVal) {
2518
0
        if (LLVM_LIKELY(O2REG(GetByVal).isObject())) {
2519
0
          CAPTURE_IP(
2520
0
              resPH = JSObject::getComputed_RJS(
2521
0
                  Handle<JSObject>::vmcast(&O2REG(GetByVal)),
2522
0
                  runtime,
2523
0
                  Handle<>(&O3REG(GetByVal))));
2524
0
          if (LLVM_UNLIKELY(resPH == ExecutionStatus::EXCEPTION)) {
2525
0
            goto exception;
2526
0
          }
2527
0
        } else {
2528
          // This is the "slow path".
2529
0
          CAPTURE_IP(
2530
0
              resPH = Interpreter::getByValTransient_RJS(
2531
0
                  runtime,
2532
0
                  Handle<>(&O2REG(GetByVal)),
2533
0
                  Handle<>(&O3REG(GetByVal))));
2534
0
          if (LLVM_UNLIKELY(resPH == ExecutionStatus::EXCEPTION)) {
2535
0
            goto exception;
2536
0
          }
2537
0
        }
2538
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2539
0
        O1REG(GetByVal) = resPH->get();
2540
0
        ip = NEXTINST(GetByVal);
2541
0
        DISPATCH;
2542
0
      }
2543
2544
0
      CASE(PutByVal) {
2545
0
        if (LLVM_LIKELY(O1REG(PutByVal).isObject())) {
2546
0
          CAPTURE_IP_ASSIGN(
2547
0
              auto putRes,
2548
0
              JSObject::putComputed_RJS(
2549
0
                  Handle<JSObject>::vmcast(&O1REG(PutByVal)),
2550
0
                  runtime,
2551
0
                  Handle<>(&O2REG(PutByVal)),
2552
0
                  Handle<>(&O3REG(PutByVal)),
2553
0
                  defaultPropOpFlags));
2554
0
          if (LLVM_UNLIKELY(putRes == ExecutionStatus::EXCEPTION)) {
2555
0
            goto exception;
2556
0
          }
2557
0
        } else {
2558
          // This is the "slow path".
2559
0
          CAPTURE_IP_ASSIGN(
2560
0
              auto retStatus,
2561
0
              Interpreter::putByValTransient_RJS(
2562
0
                  runtime,
2563
0
                  Handle<>(&O1REG(PutByVal)),
2564
0
                  Handle<>(&O2REG(PutByVal)),
2565
0
                  Handle<>(&O3REG(PutByVal)),
2566
0
                  strictMode));
2567
0
          if (LLVM_UNLIKELY(retStatus == ExecutionStatus::EXCEPTION)) {
2568
0
            goto exception;
2569
0
          }
2570
0
        }
2571
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2572
0
        ip = NEXTINST(PutByVal);
2573
0
        DISPATCH;
2574
0
      }
2575
2576
424k
      CASE(PutOwnByIndexL) {
2577
424k
        nextIP = NEXTINST(PutOwnByIndexL);
2578
424k
        idVal = ip->iPutOwnByIndexL.op3;
2579
424k
        goto putOwnByIndex;
2580
0
      }
2581
282
      CASE(PutOwnByIndex) {
2582
282
        nextIP = NEXTINST(PutOwnByIndex);
2583
282
        idVal = ip->iPutOwnByIndex.op3;
2584
282
      }
2585
425k
    putOwnByIndex: {
2586
425k
      tmpHandle = HermesValue::encodeUntrustedNumberValue(idVal);
2587
425k
      CAPTURE_IP(
2588
425k
          JSObject::defineOwnComputedPrimitive(
2589
425k
              Handle<JSObject>::vmcast(&O1REG(PutOwnByIndex)),
2590
425k
              runtime,
2591
425k
              tmpHandle,
2592
425k
              DefinePropertyFlags::getDefaultNewPropertyFlags(),
2593
425k
              Handle<>(&O2REG(PutOwnByIndex))));
2594
425k
      gcScope.flushToSmallCount(KEEP_HANDLES);
2595
425k
      tmpHandle.clear();
2596
425k
      ip = nextIP;
2597
2.12M
      DISPATCH;
2598
2.12M
    }
2599
2600
425k
      CASE_OUTOFLINE(GetPNameList);
2601
2602
511k
      CASE(GetNextPName) {
2603
511k
        {
2604
511k
          assert(
2605
511k
              vmisa<BigStorage>(O2REG(GetNextPName)) &&
2606
511k
              "GetNextPName's second op must be BigStorage");
2607
511k
          auto obj = Handle<JSObject>::vmcast(&O3REG(GetNextPName));
2608
511k
          auto arr = Handle<BigStorage>::vmcast(&O2REG(GetNextPName));
2609
511k
          uint32_t idx = O4REG(GetNextPName).getNumber();
2610
511k
          uint32_t size = O5REG(GetNextPName).getNumber();
2611
511k
          MutableHandle<JSObject> propObj{runtime};
2612
511k
          MutableHandle<SymbolID> tmpPropNameStorage{runtime};
2613
          // Loop until we find a property which is present.
2614
511k
          while (idx < size) {
2615
511k
            tmpHandle = arr->at(runtime, idx);
2616
511k
            ComputedPropertyDescriptor desc;
2617
511k
            CAPTURE_IP_ASSIGN(
2618
511k
                ExecutionStatus status,
2619
511k
                JSObject::getComputedPrimitiveDescriptor(
2620
511k
                    obj,
2621
511k
                    runtime,
2622
511k
                    tmpHandle,
2623
511k
                    propObj,
2624
511k
                    tmpPropNameStorage,
2625
511k
                    desc));
2626
511k
            if (LLVM_UNLIKELY(status == ExecutionStatus::EXCEPTION)) {
2627
0
              goto exception;
2628
0
            }
2629
511k
            if (LLVM_LIKELY(propObj))
2630
511k
              break;
2631
0
            ++idx;
2632
0
          }
2633
511k
          if (idx < size) {
2634
            // We must return the property as a string
2635
511k
            if (tmpHandle->isNumber()) {
2636
511k
              CAPTURE_IP_ASSIGN(auto status, toString_RJS(runtime, tmpHandle));
2637
511k
              assert(
2638
511k
                  status == ExecutionStatus::RETURNED &&
2639
511k
                  "toString on number cannot fail");
2640
511k
              tmpHandle = status->getHermesValue();
2641
511k
            }
2642
511k
            O4REG(GetNextPName) =
2643
511k
                HermesValue::encodeUntrustedNumberValue(idx + 1);
2644
            // Write the result last in case it is the same register as O4REG.
2645
511k
            O1REG(GetNextPName) = tmpHandle.get();
2646
511k
          } else {
2647
5
            O1REG(GetNextPName) = HermesValue::encodeUndefinedValue();
2648
5
          }
2649
511k
        }
2650
511k
        gcScope.flushToSmallCount(KEEP_HANDLES);
2651
511k
        tmpHandle.clear();
2652
511k
        ip = NEXTINST(GetNextPName);
2653
2.55M
        DISPATCH;
2654
2.55M
      }
2655
2656
6
      CASE(ToNumber) {
2657
6
        if (LLVM_LIKELY(O2REG(ToNumber).isNumber())) {
2658
0
          O1REG(ToNumber) = O2REG(ToNumber);
2659
0
          ip = NEXTINST(ToNumber);
2660
6
        } else {
2661
6
          CAPTURE_IP(res = toNumber_RJS(runtime, Handle<>(&O2REG(ToNumber))));
2662
6
          if (res == ExecutionStatus::EXCEPTION)
2663
0
            goto exception;
2664
6
          gcScope.flushToSmallCount(KEEP_HANDLES);
2665
6
          O1REG(ToNumber) = res.getValue();
2666
6
          ip = NEXTINST(ToNumber);
2667
6
        }
2668
36
        DISPATCH;
2669
36
      }
2670
2671
0
      CASE(ToNumeric) {
2672
0
        if (LLVM_LIKELY(O2REG(ToNumeric).isNumber())) {
2673
0
          O1REG(ToNumeric) = O2REG(ToNumeric);
2674
0
          ip = NEXTINST(ToNumeric);
2675
0
        } else {
2676
0
          CAPTURE_IP(res = toNumeric_RJS(runtime, Handle<>(&O2REG(ToNumeric))));
2677
0
          if (res == ExecutionStatus::EXCEPTION)
2678
0
            goto exception;
2679
0
          gcScope.flushToSmallCount(KEEP_HANDLES);
2680
0
          O1REG(ToNumeric) = res.getValue();
2681
0
          ip = NEXTINST(ToNumeric);
2682
0
        }
2683
0
        DISPATCH;
2684
0
      }
2685
2686
0
      CASE(ToInt32) {
2687
0
        CAPTURE_IP(res = toInt32_RJS(runtime, Handle<>(&O2REG(ToInt32))));
2688
0
        if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION))
2689
0
          goto exception;
2690
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2691
0
        O1REG(ToInt32) = res.getValue();
2692
0
        ip = NEXTINST(ToInt32);
2693
0
        DISPATCH;
2694
0
      }
2695
2696
0
      CASE(AddEmptyString) {
2697
0
        if (LLVM_LIKELY(O2REG(AddEmptyString).isString())) {
2698
0
          O1REG(AddEmptyString) = O2REG(AddEmptyString);
2699
0
          ip = NEXTINST(AddEmptyString);
2700
0
        } else {
2701
0
          CAPTURE_IP(
2702
0
              res = toPrimitive_RJS(
2703
0
                  runtime,
2704
0
                  Handle<>(&O2REG(AddEmptyString)),
2705
0
                  PreferredType::NONE));
2706
0
          if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION))
2707
0
            goto exception;
2708
0
          tmpHandle = res.getValue();
2709
0
          CAPTURE_IP_ASSIGN(auto strRes, toString_RJS(runtime, tmpHandle));
2710
0
          if (LLVM_UNLIKELY(strRes == ExecutionStatus::EXCEPTION))
2711
0
            goto exception;
2712
0
          tmpHandle.clear();
2713
0
          gcScope.flushToSmallCount(KEEP_HANDLES);
2714
0
          O1REG(AddEmptyString) = strRes->getHermesValue();
2715
0
          ip = NEXTINST(AddEmptyString);
2716
0
        }
2717
0
        DISPATCH;
2718
0
      }
2719
2720
511k
      CASE(Jmp) {
2721
511k
        ip = IPADD(ip->iJmp.op1);
2722
2.55M
        DISPATCH;
2723
2.55M
      }
2724
0
      CASE(JmpLong) {
2725
0
        ip = IPADD(ip->iJmpLong.op1);
2726
0
        DISPATCH;
2727
0
      }
2728
665
      CASE(JmpTrue) {
2729
665
        if (toBoolean(O2REG(JmpTrue)))
2730
100
          ip = IPADD(ip->iJmpTrue.op1);
2731
565
        else
2732
565
          ip = NEXTINST(JmpTrue);
2733
3.32k
        DISPATCH;
2734
3.32k
      }
2735
7
      CASE(JmpTrueLong) {
2736
7
        if (toBoolean(O2REG(JmpTrueLong)))
2737
7
          ip = IPADD(ip->iJmpTrueLong.op1);
2738
0
        else
2739
0
          ip = NEXTINST(JmpTrueLong);
2740
35
        DISPATCH;
2741
35
      }
2742
188
      CASE(JmpFalse) {
2743
188
        if (!toBoolean(O2REG(JmpFalse)))
2744
94
          ip = IPADD(ip->iJmpFalse.op1);
2745
94
        else
2746
94
          ip = NEXTINST(JmpFalse);
2747
940
        DISPATCH;
2748
940
      }
2749
0
      CASE(JmpFalseLong) {
2750
0
        if (!toBoolean(O2REG(JmpFalseLong)))
2751
0
          ip = IPADD(ip->iJmpFalseLong.op1);
2752
0
        else
2753
0
          ip = NEXTINST(JmpFalseLong);
2754
0
        DISPATCH;
2755
0
      }
2756
511k
      CASE(JmpUndefined) {
2757
511k
        if (O2REG(JmpUndefined).isUndefined())
2758
5
          ip = IPADD(ip->iJmpUndefined.op1);
2759
511k
        else
2760
511k
          ip = NEXTINST(JmpUndefined);
2761
2.55M
        DISPATCH;
2762
2.55M
      }
2763
0
      CASE(JmpUndefinedLong) {
2764
0
        if (O2REG(JmpUndefinedLong).isUndefined())
2765
0
          ip = IPADD(ip->iJmpUndefinedLong.op1);
2766
0
        else
2767
0
          ip = NEXTINST(JmpUndefinedLong);
2768
0
        DISPATCH;
2769
0
      }
2770
0
      INCDECOP(Inc)
2771
0
      INCDECOP(Dec)
2772
1.15k
      CASE(Add) {
2773
1.15k
        if (LLVM_LIKELY(
2774
1.15k
                O2REG(Add).isNumber() &&
2775
1.15k
                O3REG(Add).isNumber())) { /* Fast-path. */
2776
5
          INTERPRETER_FALLTHROUGH;
2777
5
          CASE(AddN) {
2778
5
            O1REG(Add) = HermesValue::encodeTrustedNumberValue(
2779
5
                O2REG(Add).getNumber() + O3REG(Add).getNumber());
2780
5
            ip = NEXTINST(Add);
2781
25
            DISPATCH;
2782
25
          }
2783
25
        }
2784
1.15k
        CAPTURE_IP(
2785
1.15k
            res = addOp_RJS(
2786
1.15k
                runtime, Handle<>(&O2REG(Add)), Handle<>(&O3REG(Add))));
2787
1.15k
        if (res == ExecutionStatus::EXCEPTION) {
2788
0
          goto exception;
2789
0
        }
2790
1.15k
        gcScope.flushToSmallCount(KEEP_HANDLES);
2791
1.15k
        O1REG(Add) = res.getValue();
2792
1.15k
        ip = NEXTINST(Add);
2793
5.72k
        DISPATCH;
2794
5.72k
      }
2795
2796
0
      CASE(BitNot) {
2797
0
        if (LLVM_LIKELY(O2REG(BitNot).isNumber())) { /* Fast-path. */
2798
0
          O1REG(BitNot) = HermesValue::encodeUntrustedNumberValue(
2799
0
              ~hermes::truncateToInt32(O2REG(BitNot).getNumber()));
2800
0
          ip = NEXTINST(BitNot);
2801
0
          DISPATCH;
2802
0
        }
2803
0
        CAPTURE_IP(res = doBitNotSlowPath(runtime, Handle<>(&O2REG(BitNot))));
2804
0
        if (res == ExecutionStatus::EXCEPTION) {
2805
0
          goto exception;
2806
0
        }
2807
0
        O1REG(BitNot) = *res;
2808
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2809
0
        ip = NEXTINST(BitNot);
2810
0
        DISPATCH;
2811
0
      }
2812
2813
0
      CASE(GetArgumentsLength) {
2814
        // If the arguments object hasn't been created yet.
2815
0
        if (O2REG(GetArgumentsLength).isUndefined()) {
2816
0
          O1REG(GetArgumentsLength) =
2817
0
              HermesValue::encodeUntrustedNumberValue(FRAME.getArgCount());
2818
0
          ip = NEXTINST(GetArgumentsLength);
2819
0
          DISPATCH;
2820
0
        }
2821
        // The arguments object has been created, so this is a regular property
2822
        // get.
2823
0
        assert(
2824
0
            O2REG(GetArgumentsLength).isObject() &&
2825
0
            "arguments lazy register is not an object");
2826
0
        CAPTURE_IP(
2827
0
            resPH = JSObject::getNamed_RJS(
2828
0
                Handle<JSObject>::vmcast(&O2REG(GetArgumentsLength)),
2829
0
                runtime,
2830
0
                Predefined::getSymbolID(Predefined::length)));
2831
0
        if (resPH == ExecutionStatus::EXCEPTION) {
2832
0
          goto exception;
2833
0
        }
2834
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2835
0
        O1REG(GetArgumentsLength) = resPH->get();
2836
0
        ip = NEXTINST(GetArgumentsLength);
2837
0
        DISPATCH;
2838
0
      }
2839
2840
0
      CASE(GetArgumentsPropByVal) {
2841
        // If the arguments object hasn't been created yet and we have a
2842
        // valid integer index, we use the fast path.
2843
0
        if (O3REG(GetArgumentsPropByVal).isUndefined()) {
2844
          // If this is an integer index.
2845
0
          if (auto index = toArrayIndexFastPath(O2REG(GetArgumentsPropByVal))) {
2846
            // Is this an existing argument?
2847
0
            if (*index < FRAME.getArgCount()) {
2848
0
              O1REG(GetArgumentsPropByVal) = FRAME.getArgRef(*index);
2849
0
              ip = NEXTINST(GetArgumentsPropByVal);
2850
0
              DISPATCH;
2851
0
            }
2852
0
          }
2853
0
        }
2854
        // Slow path.
2855
0
        CAPTURE_IP_ASSIGN(
2856
0
            auto res,
2857
0
            getArgumentsPropByValSlowPath_RJS(
2858
0
                runtime,
2859
0
                &O3REG(GetArgumentsPropByVal),
2860
0
                &O2REG(GetArgumentsPropByVal),
2861
0
                FRAME.getCalleeClosureHandleUnsafe(),
2862
0
                strictMode));
2863
0
        if (res == ExecutionStatus::EXCEPTION) {
2864
0
          goto exception;
2865
0
        }
2866
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2867
0
        O1REG(GetArgumentsPropByVal) = res->getHermesValue();
2868
0
        ip = NEXTINST(GetArgumentsPropByVal);
2869
0
        DISPATCH;
2870
0
      }
2871
2872
0
      CASE(ReifyArguments) {
2873
        // If the arguments object was already created, do nothing.
2874
0
        if (!O1REG(ReifyArguments).isUndefined()) {
2875
0
          assert(
2876
0
              O1REG(ReifyArguments).isObject() &&
2877
0
              "arguments lazy register is not an object");
2878
0
          ip = NEXTINST(ReifyArguments);
2879
0
          DISPATCH;
2880
0
        }
2881
0
        CAPTURE_IP(
2882
0
            resArgs = reifyArgumentsSlowPath(
2883
0
                runtime, FRAME.getCalleeClosureHandleUnsafe(), strictMode));
2884
0
        if (LLVM_UNLIKELY(resArgs == ExecutionStatus::EXCEPTION)) {
2885
0
          goto exception;
2886
0
        }
2887
0
        O1REG(ReifyArguments) = resArgs->getHermesValue();
2888
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2889
0
        ip = NEXTINST(ReifyArguments);
2890
0
        DISPATCH;
2891
0
      }
2892
2893
376
      CASE(NewObject) {
2894
        // Create a new object using the built-in constructor. Note that the
2895
        // built-in constructor is empty, so we don't actually need to call
2896
        // it.
2897
376
        CAPTURE_IP(
2898
376
            O1REG(NewObject) = JSObject::create(runtime).getHermesValue());
2899
376
        assert(
2900
376
            gcScope.getHandleCountDbg() == KEEP_HANDLES &&
2901
376
            "Should not create handles.");
2902
376
        ip = NEXTINST(NewObject);
2903
1.88k
        DISPATCH;
2904
1.88k
      }
2905
0
      CASE(NewObjectWithParent) {
2906
0
        CAPTURE_IP(
2907
0
            O1REG(NewObjectWithParent) =
2908
0
                JSObject::create(
2909
0
                    runtime,
2910
0
                    O2REG(NewObjectWithParent).isObject()
2911
0
                        ? Handle<JSObject>::vmcast(&O2REG(NewObjectWithParent))
2912
0
                        : O2REG(NewObjectWithParent).isNull()
2913
0
                        ? Runtime::makeNullHandle<JSObject>()
2914
0
                        : Handle<JSObject>::vmcast(&runtime.objectPrototype))
2915
0
                    .getHermesValue());
2916
0
        assert(
2917
0
            gcScope.getHandleCountDbg() == KEEP_HANDLES &&
2918
0
            "Should not create handles.");
2919
0
        ip = NEXTINST(NewObjectWithParent);
2920
0
        DISPATCH;
2921
0
      }
2922
2923
0
      CASE(NewObjectWithBuffer) {
2924
0
        CAPTURE_IP(
2925
0
            resPH = Interpreter::createObjectFromBuffer(
2926
0
                runtime,
2927
0
                curCodeBlock,
2928
0
                ip->iNewObjectWithBuffer.op3,
2929
0
                ip->iNewObjectWithBuffer.op4,
2930
0
                ip->iNewObjectWithBuffer.op5));
2931
0
        if (LLVM_UNLIKELY(resPH == ExecutionStatus::EXCEPTION)) {
2932
0
          goto exception;
2933
0
        }
2934
0
        O1REG(NewObjectWithBuffer) = resPH->get();
2935
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2936
0
        ip = NEXTINST(NewObjectWithBuffer);
2937
0
        DISPATCH;
2938
0
      }
2939
2940
0
      CASE(NewObjectWithBufferLong) {
2941
0
        CAPTURE_IP(
2942
0
            resPH = Interpreter::createObjectFromBuffer(
2943
0
                runtime,
2944
0
                curCodeBlock,
2945
0
                ip->iNewObjectWithBufferLong.op3,
2946
0
                ip->iNewObjectWithBufferLong.op4,
2947
0
                ip->iNewObjectWithBufferLong.op5));
2948
0
        if (LLVM_UNLIKELY(resPH == ExecutionStatus::EXCEPTION)) {
2949
0
          goto exception;
2950
0
        }
2951
0
        O1REG(NewObjectWithBufferLong) = resPH->get();
2952
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2953
0
        ip = NEXTINST(NewObjectWithBufferLong);
2954
0
        DISPATCH;
2955
0
      }
2956
2957
95
      CASE(NewArray) {
2958
        // Create a new array using the built-in constructor. Note that the
2959
        // built-in constructor is empty, so we don't actually need to call
2960
        // it.
2961
95
        {
2962
95
          CAPTURE_IP_ASSIGN(
2963
95
              auto createRes,
2964
95
              JSArray::create(runtime, ip->iNewArray.op2, ip->iNewArray.op2));
2965
95
          if (createRes == ExecutionStatus::EXCEPTION) {
2966
0
            goto exception;
2967
0
          }
2968
95
          O1REG(NewArray) = createRes->getHermesValue();
2969
95
        }
2970
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
2971
95
        ip = NEXTINST(NewArray);
2972
475
        DISPATCH;
2973
475
      }
2974
2975
6
      CASE(NewArrayWithBuffer) {
2976
6
        CAPTURE_IP(
2977
6
            resPH = Interpreter::createArrayFromBuffer(
2978
6
                runtime,
2979
6
                curCodeBlock,
2980
6
                ip->iNewArrayWithBuffer.op2,
2981
6
                ip->iNewArrayWithBuffer.op3,
2982
6
                ip->iNewArrayWithBuffer.op4));
2983
6
        if (LLVM_UNLIKELY(resPH == ExecutionStatus::EXCEPTION)) {
2984
0
          goto exception;
2985
0
        }
2986
6
        O1REG(NewArrayWithBuffer) = resPH->get();
2987
6
        gcScope.flushToSmallCount(KEEP_HANDLES);
2988
6
        tmpHandle.clear();
2989
6
        ip = NEXTINST(NewArrayWithBuffer);
2990
30
        DISPATCH;
2991
30
      }
2992
2993
0
      CASE(NewArrayWithBufferLong) {
2994
0
        CAPTURE_IP(
2995
0
            resPH = Interpreter::createArrayFromBuffer(
2996
0
                runtime,
2997
0
                curCodeBlock,
2998
0
                ip->iNewArrayWithBufferLong.op2,
2999
0
                ip->iNewArrayWithBufferLong.op3,
3000
0
                ip->iNewArrayWithBufferLong.op4));
3001
0
        if (LLVM_UNLIKELY(resPH == ExecutionStatus::EXCEPTION)) {
3002
0
          goto exception;
3003
0
        }
3004
0
        O1REG(NewArrayWithBufferLong) = resPH->get();
3005
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
3006
0
        tmpHandle.clear();
3007
0
        ip = NEXTINST(NewArrayWithBufferLong);
3008
0
        DISPATCH;
3009
0
      }
3010
3011
564
      CASE(CreateThis) {
3012
        // Registers: output, prototype, closure.
3013
564
        if (LLVM_UNLIKELY(!vmisa<Callable>(O3REG(CreateThis)))) {
3014
0
          CAPTURE_IP(runtime.raiseTypeError("constructor is not callable"));
3015
0
          goto exception;
3016
0
        }
3017
564
        CAPTURE_IP_ASSIGN(
3018
564
            auto res,
3019
564
            Callable::newObject(
3020
564
                Handle<Callable>::vmcast(&O3REG(CreateThis)),
3021
564
                runtime,
3022
564
                Handle<JSObject>::vmcast(
3023
564
                    O2REG(CreateThis).isObject() ? &O2REG(CreateThis)
3024
564
                                                 : &runtime.objectPrototype)));
3025
564
        if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
3026
0
          goto exception;
3027
0
        }
3028
564
        gcScope.flushToSmallCount(KEEP_HANDLES);
3029
564
        O1REG(CreateThis) = res->getHermesValue();
3030
564
        ip = NEXTINST(CreateThis);
3031
2.82k
        DISPATCH;
3032
2.82k
      }
3033
3034
564
      CASE(SelectObject) {
3035
        // Registers: output, thisObject, constructorReturnValue.
3036
564
        O1REG(SelectObject) = O3REG(SelectObject).isObject()
3037
564
            ? O3REG(SelectObject)
3038
564
            : O2REG(SelectObject);
3039
564
        ip = NEXTINST(SelectObject);
3040
2.82k
        DISPATCH;
3041
2.82k
      }
3042
3043
564
      CASE(Eq)
3044
512k
      CASE(Neq) {
3045
512k
        CAPTURE_IP_ASSIGN(
3046
512k
            auto eqRes,
3047
512k
            abstractEqualityTest_RJS(
3048
512k
                runtime, Handle<>(&O2REG(Eq)), Handle<>(&O3REG(Eq))));
3049
512k
        if (eqRes == ExecutionStatus::EXCEPTION) {
3050
0
          goto exception;
3051
0
        }
3052
512k
        gcScope.flushToSmallCount(KEEP_HANDLES);
3053
512k
        O1REG(Eq) = HermesValue::encodeBoolValue(
3054
512k
            ip->opCode == OpCode::Eq ? *eqRes : !*eqRes);
3055
512k
        ip = NEXTINST(Eq);
3056
2.56M
        DISPATCH;
3057
2.56M
      }
3058
0
      CASE(StrictEq) {
3059
0
        O1REG(StrictEq) = HermesValue::encodeBoolValue(
3060
0
            strictEqualityTest(O2REG(StrictEq), O3REG(StrictEq)));
3061
0
        ip = NEXTINST(StrictEq);
3062
0
        DISPATCH;
3063
0
      }
3064
0
      CASE(StrictNeq) {
3065
0
        O1REG(StrictNeq) = HermesValue::encodeBoolValue(
3066
0
            !strictEqualityTest(O2REG(StrictNeq), O3REG(StrictNeq)));
3067
0
        ip = NEXTINST(StrictNeq);
3068
0
        DISPATCH;
3069
0
      }
3070
1
      CASE(Not) {
3071
1
        O1REG(Not) = HermesValue::encodeBoolValue(!toBoolean(O2REG(Not)));
3072
1
        ip = NEXTINST(Not);
3073
5
        DISPATCH;
3074
5
      }
3075
7.13k
      CASE(Negate) {
3076
7.13k
        if (LLVM_LIKELY(O2REG(Negate).isNumber())) {
3077
7.05k
          O1REG(Negate) = HermesValue::encodeUntrustedNumberValue(
3078
7.05k
              -O2REG(Negate).getNumber());
3079
7.05k
          ip = NEXTINST(Negate);
3080
35.2k
          DISPATCH;
3081
35.2k
        }
3082
7.13k
        CAPTURE_IP(res = doNegateSlowPath(runtime, Handle<>(&O2REG(Negate))));
3083
7.13k
        if (res == ExecutionStatus::EXCEPTION)
3084
0
          goto exception;
3085
7.13k
        O1REG(Negate) = *res;
3086
7.13k
        gcScope.flushToSmallCount(KEEP_HANDLES);
3087
7.13k
        ip = NEXTINST(Negate);
3088
7.13k
        DISPATCH;
3089
410
      }
3090
1.12k
      CASE(TypeOf) {
3091
1.12k
        CAPTURE_IP(O1REG(TypeOf) = typeOf(runtime, Handle<>(&O2REG(TypeOf))));
3092
1.12k
        ip = NEXTINST(TypeOf);
3093
5.64k
        DISPATCH;
3094
5.64k
      }
3095
14
      CASE(Mod) {
3096
14
        if (LLVM_LIKELY(O2REG(Mod).isNumber() && O3REG(Mod).isNumber())) {
3097
          /* Fast-path. */
3098
13
          O1REG(Mod) = HermesValue::encodeUntrustedNumberValue(
3099
13
              doMod(O2REG(Mod).getNumber(), O3REG(Mod).getNumber()));
3100
13
          ip = NEXTINST(Mod);
3101
65
          DISPATCH;
3102
65
        }
3103
14
        CAPTURE_IP(
3104
14
            res = doOperSlowPath<doMod>(
3105
14
                runtime, Handle<>(&O2REG(Mod)), Handle<>(&O3REG(Mod))));
3106
14
        if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
3107
0
          goto exception;
3108
0
        }
3109
14
        O1REG(Mod) = *res;
3110
14
        gcScope.flushToSmallCount(KEEP_HANDLES);
3111
14
        ip = NEXTINST(Mod);
3112
14
        DISPATCH;
3113
5
      }
3114
0
      CASE(InstanceOf) {
3115
0
        CAPTURE_IP_ASSIGN(
3116
0
            auto result,
3117
0
            instanceOfOperator_RJS(
3118
0
                runtime,
3119
0
                Handle<>(&O2REG(InstanceOf)),
3120
0
                Handle<>(&O3REG(InstanceOf))));
3121
0
        if (LLVM_UNLIKELY(result == ExecutionStatus::EXCEPTION)) {
3122
0
          goto exception;
3123
0
        }
3124
0
        O1REG(InstanceOf) = HermesValue::encodeBoolValue(*result);
3125
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
3126
0
        ip = NEXTINST(InstanceOf);
3127
0
        DISPATCH;
3128
0
      }
3129
0
      CASE(IsIn) {
3130
0
        {
3131
0
          if (LLVM_UNLIKELY(!O3REG(IsIn).isObject())) {
3132
0
            CAPTURE_IP(runtime.raiseTypeError(
3133
0
                "right operand of 'in' is not an object"));
3134
0
            goto exception;
3135
0
          }
3136
0
          CAPTURE_IP_ASSIGN(
3137
0
              auto cr,
3138
0
              JSObject::hasComputed(
3139
0
                  Handle<JSObject>::vmcast(&O3REG(IsIn)),
3140
0
                  runtime,
3141
0
                  Handle<>(&O2REG(IsIn))));
3142
0
          if (cr == ExecutionStatus::EXCEPTION) {
3143
0
            goto exception;
3144
0
          }
3145
0
          O1REG(IsIn) = HermesValue::encodeBoolValue(*cr);
3146
0
        }
3147
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
3148
0
        ip = NEXTINST(IsIn);
3149
0
        DISPATCH;
3150
0
      }
3151
3152
188
      CASE(PutNewOwnByIdShort) {
3153
188
        nextIP = NEXTINST(PutNewOwnByIdShort);
3154
188
        idVal = ip->iPutNewOwnByIdShort.op3;
3155
188
        goto putOwnById;
3156
0
      }
3157
0
      CASE(PutNewOwnNEByIdLong)
3158
0
      CASE(PutNewOwnByIdLong) {
3159
0
        nextIP = NEXTINST(PutNewOwnByIdLong);
3160
0
        idVal = ip->iPutNewOwnByIdLong.op3;
3161
0
        goto putOwnById;
3162
0
      }
3163
0
      CASE(PutNewOwnNEById)
3164
0
      CASE(PutNewOwnById) {
3165
0
        nextIP = NEXTINST(PutNewOwnById);
3166
0
        idVal = ip->iPutNewOwnById.op3;
3167
0
      }
3168
188
    putOwnById: {
3169
188
      assert(
3170
188
          O1REG(PutNewOwnById).isObject() &&
3171
188
          "Object argument of PutNewOwnById must be an object");
3172
188
      CAPTURE_IP_ASSIGN(
3173
188
          auto res,
3174
188
          JSObject::defineNewOwnProperty(
3175
188
              Handle<JSObject>::vmcast(&O1REG(PutNewOwnById)),
3176
188
              runtime,
3177
188
              ID(idVal),
3178
188
              ip->opCode <= OpCode::PutNewOwnByIdLong
3179
188
                  ? PropertyFlags::defaultNewNamedPropertyFlags()
3180
188
                  : PropertyFlags::nonEnumerablePropertyFlags(),
3181
188
              Handle<>(&O2REG(PutNewOwnById))));
3182
188
      if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
3183
0
        goto exception;
3184
0
      }
3185
188
      gcScope.flushToSmallCount(KEEP_HANDLES);
3186
188
      ip = nextIP;
3187
940
      DISPATCH;
3188
940
    }
3189
3190
0
      CASE(DelByIdLong) {
3191
0
        idVal = ip->iDelByIdLong.op3;
3192
0
        nextIP = NEXTINST(DelByIdLong);
3193
0
        goto DelById;
3194
940
      }
3195
3196
273
      CASE(DelById) {
3197
273
        idVal = ip->iDelById.op3;
3198
273
        nextIP = NEXTINST(DelById);
3199
273
      }
3200
273
    DelById: {
3201
273
      if (LLVM_LIKELY(O2REG(DelById).isObject())) {
3202
273
        CAPTURE_IP_ASSIGN(
3203
273
            auto status,
3204
273
            JSObject::deleteNamed(
3205
273
                Handle<JSObject>::vmcast(&O2REG(DelById)),
3206
273
                runtime,
3207
273
                ID(idVal),
3208
273
                defaultPropOpFlags));
3209
273
        if (LLVM_UNLIKELY(status == ExecutionStatus::EXCEPTION)) {
3210
0
          goto exception;
3211
0
        }
3212
273
        O1REG(DelById) = HermesValue::encodeBoolValue(status.getValue());
3213
273
      } else {
3214
        // This is the "slow path".
3215
0
        CAPTURE_IP(res = toObject(runtime, Handle<>(&O2REG(DelById))));
3216
0
        if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
3217
          // If an exception is thrown, likely we are trying to convert
3218
          // undefined/null to an object. Passing over the name of the property
3219
          // so that we could emit more meaningful error messages.
3220
0
          CAPTURE_IP(amendPropAccessErrorMsgWithPropName(
3221
0
              runtime, Handle<>(&O2REG(DelById)), "delete", ID(idVal)));
3222
0
          goto exception;
3223
0
        }
3224
0
        tmpHandle = res.getValue();
3225
0
        CAPTURE_IP_ASSIGN(
3226
0
            auto status,
3227
0
            JSObject::deleteNamed(
3228
0
                Handle<JSObject>::vmcast(tmpHandle),
3229
0
                runtime,
3230
0
                ID(idVal),
3231
0
                defaultPropOpFlags));
3232
0
        if (LLVM_UNLIKELY(status == ExecutionStatus::EXCEPTION)) {
3233
0
          goto exception;
3234
0
        }
3235
0
        O1REG(DelById) = HermesValue::encodeBoolValue(status.getValue());
3236
0
        tmpHandle.clear();
3237
0
      }
3238
273
      gcScope.flushToSmallCount(KEEP_HANDLES);
3239
273
      ip = nextIP;
3240
1.36k
      DISPATCH;
3241
1.36k
    }
3242
3243
0
      CASE(DelByVal) {
3244
0
        if (LLVM_LIKELY(O2REG(DelByVal).isObject())) {
3245
0
          CAPTURE_IP_ASSIGN(
3246
0
              auto status,
3247
0
              JSObject::deleteComputed(
3248
0
                  Handle<JSObject>::vmcast(&O2REG(DelByVal)),
3249
0
                  runtime,
3250
0
                  Handle<>(&O3REG(DelByVal)),
3251
0
                  defaultPropOpFlags));
3252
0
          if (LLVM_UNLIKELY(status == ExecutionStatus::EXCEPTION)) {
3253
0
            goto exception;
3254
0
          }
3255
0
          O1REG(DelByVal) = HermesValue::encodeBoolValue(status.getValue());
3256
0
        } else {
3257
          // This is the "slow path".
3258
0
          CAPTURE_IP(res = toObject(runtime, Handle<>(&O2REG(DelByVal))));
3259
0
          if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
3260
0
            goto exception;
3261
0
          }
3262
0
          tmpHandle = res.getValue();
3263
0
          CAPTURE_IP_ASSIGN(
3264
0
              auto status,
3265
0
              JSObject::deleteComputed(
3266
0
                  Handle<JSObject>::vmcast(tmpHandle),
3267
0
                  runtime,
3268
0
                  Handle<>(&O3REG(DelByVal)),
3269
0
                  defaultPropOpFlags));
3270
0
          if (LLVM_UNLIKELY(status == ExecutionStatus::EXCEPTION)) {
3271
0
            goto exception;
3272
0
          }
3273
0
          O1REG(DelByVal) = HermesValue::encodeBoolValue(status.getValue());
3274
0
        }
3275
0
        gcScope.flushToSmallCount(KEEP_HANDLES);
3276
0
        tmpHandle.clear();
3277
0
        ip = NEXTINST(DelByVal);
3278
0
        DISPATCH;
3279
0
      }
3280
1.03k
      CASE(CreateRegExp) {
3281
1.03k
        {
3282
          // Create the RegExp object.
3283
1.03k
          CAPTURE_IP(
3284
1.03k
              O1REG(CreateRegExp) = JSRegExp::create(runtime).getHermesValue());
3285
1.03k
          auto re = Handle<JSRegExp>::vmcast(&O1REG(CreateRegExp));
3286
          // Initialize the regexp.
3287
1.03k
          CAPTURE_IP_ASSIGN(
3288
1.03k
              auto pattern,
3289
1.03k
              runtime.makeHandle(curCodeBlock->getRuntimeModule()
3290
1.03k
                                     ->getStringPrimFromStringIDMayAllocate(
3291
1.03k
                                         ip->iCreateRegExp.op2)));
3292
1.03k
          CAPTURE_IP_ASSIGN(
3293
1.03k
              auto flags,
3294
1.03k
              runtime.makeHandle(curCodeBlock->getRuntimeModule()
3295
1.03k
                                     ->getStringPrimFromStringIDMayAllocate(
3296
1.03k
                                         ip->iCreateRegExp.op3)));
3297
1.03k
          CAPTURE_IP_ASSIGN(
3298
1.03k
              auto bytecode,
3299
1.03k
              curCodeBlock->getRuntimeModule()->getRegExpBytecodeFromRegExpID(
3300
1.03k
                  ip->iCreateRegExp.op4));
3301
1.03k
          CAPTURE_IP(
3302
1.03k
              JSRegExp::initialize(re, runtime, pattern, flags, bytecode));
3303
1.03k
        }
3304
1.03k
        gcScope.flushToSmallCount(KEEP_HANDLES);
3305
1.03k
        ip = NEXTINST(CreateRegExp);
3306
5.16k
        DISPATCH;
3307
5.16k
      }
3308
3309
0
      CASE(SwitchImm) {
3310
0
        if (LLVM_LIKELY(O1REG(SwitchImm).isNumber())) {
3311
0
          double numVal = O1REG(SwitchImm).getNumber();
3312
0
          uint32_t uintVal = (uint32_t)numVal;
3313
0
          if (LLVM_LIKELY(numVal == uintVal) && // Only integers.
3314
0
              LLVM_LIKELY(uintVal >= ip->iSwitchImm.op4) && // Bounds checking.
3315
0
              LLVM_LIKELY(uintVal <= ip->iSwitchImm.op5)) // Bounds checking.
3316
0
          {
3317
            // Calculate the offset into the bytecode where the jump table for
3318
            // this SwitchImm starts.
3319
0
            const uint8_t *tablestart = (const uint8_t *)llvh::alignAddr(
3320
0
                (const uint8_t *)ip + ip->iSwitchImm.op2, sizeof(uint32_t));
3321
3322
            // Read the offset from the table.
3323
            // Must be signed to account for backwards branching.
3324
0
            const int32_t *loc =
3325
0
                (const int32_t *)tablestart + uintVal - ip->iSwitchImm.op4;
3326
3327
0
            ip = IPADD(*loc);
3328
0
            DISPATCH;
3329
0
          }
3330
0
        }
3331
        // Wrong type or out of range, jump to default.
3332
0
        ip = IPADD(ip->iSwitchImm.op3);
3333
0
        DISPATCH;
3334
0
      }
3335
800k
      LOAD_CONST(
3336
800k
          LoadConstUInt8,
3337
800k
          HermesValue::encodeTrustedNumberValue(ip->iLoadConstUInt8.op2));
3338
3.15M
      LOAD_CONST(
3339
3.15M
          LoadConstInt,
3340
3.15M
          HermesValue::encodeTrustedNumberValue(ip->iLoadConstInt.op2));
3341
3.15M
      LOAD_CONST(
3342
41.3k
          LoadConstDouble,
3343
41.3k
          HermesValue::encodeUntrustedNumberValue(ip->iLoadConstDouble.op2));
3344
3.80M
      LOAD_CONST_CAPTURE_IP(
3345
3.80M
          LoadConstString,
3346
3.80M
          HermesValue::encodeStringValue(
3347
3.80M
              curCodeBlock->getRuntimeModule()
3348
3.80M
                  ->getStringPrimFromStringIDMayAllocate(
3349
3.80M
                      ip->iLoadConstString.op2)));
3350
3.80M
      LOAD_CONST_CAPTURE_IP(
3351
0
          LoadConstStringLongIndex,
3352
0
          HermesValue::encodeStringValue(
3353
0
              curCodeBlock->getRuntimeModule()
3354
0
                  ->getStringPrimFromStringIDMayAllocate(
3355
0
                      ip->iLoadConstStringLongIndex.op2)));
3356
0
      LOAD_CONST(LoadConstEmpty, HermesValue::encodeEmptyValue());
3357
10.4k
      LOAD_CONST(LoadConstUndefined, HermesValue::encodeUndefinedValue());
3358
10.4k
      LOAD_CONST(LoadConstNull, HermesValue::encodeNullValue());
3359
4.51k
      LOAD_CONST(LoadConstTrue, HermesValue::encodeBoolValue(true));
3360
1.18k
      LOAD_CONST(LoadConstFalse, HermesValue::encodeBoolValue(false));
3361
2.31M
      LOAD_CONST(LoadConstZero, HermesValue::encodeTrustedNumberValue(0));
3362
2.31M
      CASE(LoadConstBigInt) {
3363
511k
        idVal = ip->iLoadConstBigInt.op2;
3364
511k
        nextIP = NEXTINST(LoadConstBigInt);
3365
511k
        goto doLoadConstBigInt;
3366
2.31M
      }
3367
0
      CASE(LoadConstBigIntLongIndex) {
3368
0
        idVal = ip->iLoadConstBigIntLongIndex.op2;
3369
0
        nextIP = NEXTINST(LoadConstBigIntLongIndex);
3370
0
        goto doLoadConstBigInt;
3371
2.31M
      }
3372
511k
    doLoadConstBigInt: {
3373
511k
      CAPTURE_IP_ASSIGN(
3374
511k
          auto res,
3375
511k
          BigIntPrimitive::fromBytes(
3376
511k
              runtime,
3377
511k
              curCodeBlock->getRuntimeModule()->getBigIntBytesFromBigIntId(
3378
511k
                  idVal)));
3379
511k
      if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
3380
0
        goto exception;
3381
0
      }
3382
      // It is safe to access O1REG(LoadConstBigInt) or
3383
      // O1REG(LoadConstBigIntLongIndex) here as both instructions' O1 operands
3384
      // are the same size and live in the same offset w.r.t. the start of the
3385
      // instruction.
3386
511k
      O1REG(LoadConstBigInt) = std::move(*res);
3387
511k
      ip = nextIP;
3388
2.55M
      DISPATCH;
3389
2.55M
    }
3390
511k
      BINOP(Sub);
3391
366
      BINOP(Mul);
3392
11
      BINOP(Div);
3393
      // Can't do BINOP(Mod) as there's no ModN opcode.
3394
11
      BITWISEBINOP(BitAnd);
3395
0
      BITWISEBINOP(BitOr);
3396
0
      BITWISEBINOP(BitXor);
3397
0
      SHIFTOP(LShift);
3398
0
      SHIFTOP(RShift);
3399
0
      SHIFTOP(URshift);
3400
4.09M
      CONDOP(Less, <, lessOp_RJS);
3401
4.09M
      CONDOP(LessEq, <=, lessEqualOp_RJS);
3402
0
      CONDOP(Greater, >, greaterOp_RJS);
3403
0
      CONDOP(GreaterEq, >=, greaterEqualOp_RJS);
3404
0
      JCOND(Less, <, lessOp_RJS);
3405
0
      JCOND(LessEqual, <=, lessEqualOp_RJS);
3406
0
      JCOND(Greater, >, greaterOp_RJS);
3407
0
      JCOND(GreaterEqual, >=, greaterEqualOp_RJS);
3408
3409
1.12k
      JCOND_STRICT_EQ_IMPL(
3410
1.12k
          JStrictEqual, , IPADD(ip->iJStrictEqual.op1), NEXTINST(JStrictEqual));
3411
1.12k
      JCOND_STRICT_EQ_IMPL(
3412
0
          JStrictEqual,
3413
0
          Long,
3414
0
          IPADD(ip->iJStrictEqualLong.op1),
3415
0
          NEXTINST(JStrictEqualLong));
3416
2.25k
      JCOND_STRICT_EQ_IMPL(
3417
2.25k
          JStrictNotEqual,
3418
2.25k
          ,
3419
2.25k
          NEXTINST(JStrictNotEqual),
3420
2.25k
          IPADD(ip->iJStrictNotEqual.op1));
3421
2.25k
      JCOND_STRICT_EQ_IMPL(
3422
0
          JStrictNotEqual,
3423
0
          Long,
3424
0
          NEXTINST(JStrictNotEqualLong),
3425
0
          IPADD(ip->iJStrictNotEqualLong.op1));
3426
3427
1.50k
      JCOND_EQ_IMPL(JEqual, , IPADD(ip->iJEqual.op1), NEXTINST(JEqual));
3428
1.50k
      JCOND_EQ_IMPL(
3429
0
          JEqual, Long, IPADD(ip->iJEqualLong.op1), NEXTINST(JEqualLong));
3430
0
      JCOND_EQ_IMPL(
3431
0
          JNotEqual, , NEXTINST(JNotEqual), IPADD(ip->iJNotEqual.op1));
3432
0
      JCOND_EQ_IMPL(
3433
0
          JNotEqual,
3434
0
          Long,
3435
0
          NEXTINST(JNotEqualLong),
3436
0
          IPADD(ip->iJNotEqualLong.op1));
3437
3438
0
      CASE_OUTOFLINE(PutOwnByVal);
3439
0
      CASE_OUTOFLINE(PutOwnGetterSetterByVal);
3440
0
      CASE_OUTOFLINE(DirectEval);
3441
3442
0
      CASE_OUTOFLINE(IteratorBegin);
3443
0
      CASE_OUTOFLINE(IteratorNext);
3444
0
      CASE(IteratorClose) {
3445
0
        if (LLVM_UNLIKELY(O1REG(IteratorClose).isObject())) {
3446
          // The iterator must be closed if it's still an object.
3447
          // That means it was never an index and is not done iterating (a state
3448
          // which is indicated by `undefined`).
3449
0
          CAPTURE_IP_ASSIGN(
3450
0
              auto res,
3451
0
              iteratorClose(
3452
0
                  runtime,
3453
0
                  Handle<JSObject>::vmcast(&O1REG(IteratorClose)),
3454
0
                  Runtime::getEmptyValue()));
3455
0
          if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
3456
0
            if (ip->iIteratorClose.op2 &&
3457
0
                !isUncatchableError(runtime.thrownValue_)) {
3458
              // Ignore inner exception.
3459
0
              runtime.clearThrownValue();
3460
0
            } else {
3461
0
              goto exception;
3462
0
            }
3463
0
          }
3464
0
          gcScope.flushToSmallCount(KEEP_HANDLES);
3465
0
        }
3466
0
        ip = NEXTINST(IteratorClose);
3467
0
        DISPATCH;
3468
0
      }
3469
3470
#ifdef HERMES_RUN_WASM
3471
      // Asm.js/Wasm Intrinsics
3472
      CASE(Add32) {
3473
        O1REG(Add32) = HermesValue::encodeUntrustedNumberValue(
3474
            (int32_t)(int64_t)(O2REG(Add32).getNumber() +
3475
                               O3REG(Add32).getNumber()));
3476
        ip = NEXTINST(Add32);
3477
        DISPATCH;
3478
      }
3479
      CASE(Sub32) {
3480
        O1REG(Sub32) = HermesValue::encodeUntrustedNumberValue(
3481
            (int32_t)(int64_t)(O2REG(Sub32).getNumber() -
3482
                               O3REG(Sub32).getNumber()));
3483
        ip = NEXTINST(Sub32);
3484
        DISPATCH;
3485
      }
3486
      CASE(Mul32) {
3487
        // Signedness matters for multiplication, but low 32 bits are the same
3488
        // regardless of signedness.
3489
        const uint32_t arg0 = (uint32_t)(int32_t)(O2REG(Mul32).getNumber());
3490
        const uint32_t arg1 = (uint32_t)(int32_t)(O3REG(Mul32).getNumber());
3491
        O1REG(Mul32) =
3492
            HermesValue::encodeUntrustedNumberValue((int32_t)(arg0 * arg1));
3493
        ip = NEXTINST(Mul32);
3494
        DISPATCH;
3495
      }
3496
      CASE(Divi32) {
3497
        const int32_t arg0 = (int32_t)(O2REG(Divi32).getNumber());
3498
        const int32_t arg1 = (int32_t)(O3REG(Divi32).getNumber());
3499
        O1REG(Divi32) = HermesValue::encodeUntrustedNumberValue(arg0 / arg1);
3500
        ip = NEXTINST(Divi32);
3501
        DISPATCH;
3502
      }
3503
      CASE(Divu32) {
3504
        const uint32_t arg0 = (uint32_t)(int32_t)(O2REG(Divu32).getNumber());
3505
        const uint32_t arg1 = (uint32_t)(int32_t)(O3REG(Divu32).getNumber());
3506
        O1REG(Divu32) =
3507
            HermesValue::encodeUntrustedNumberValue((int32_t)(arg0 / arg1));
3508
        ip = NEXTINST(Divu32);
3509
        DISPATCH;
3510
      }
3511
3512
      CASE(Loadi8) {
3513
        auto *mem = vmcast<JSTypedArrayBase>(O2REG(Loadi8));
3514
        int8_t *basePtr = reinterpret_cast<int8_t *>(mem->begin(runtime));
3515
        const uint32_t addr = (uint32_t)(int32_t)(O3REG(Loadi8).getNumber());
3516
        O1REG(Loadi8) = HermesValue::encodeUntrustedNumberValue(basePtr[addr]);
3517
        ip = NEXTINST(Loadi8);
3518
        DISPATCH;
3519
      }
3520
      CASE(Loadu8) {
3521
        auto *mem = vmcast<JSTypedArrayBase>(O2REG(Loadu8));
3522
        uint8_t *basePtr = reinterpret_cast<uint8_t *>(mem->begin(runtime));
3523
        const uint32_t addr = (uint32_t)(int32_t)(O3REG(Loadu8).getNumber());
3524
        O1REG(Loadu8) = HermesValue::encodeUntrustedNumberValue(basePtr[addr]);
3525
        ip = NEXTINST(Loadu8);
3526
        DISPATCH;
3527
      }
3528
      CASE(Loadi16) {
3529
        auto *mem = vmcast<JSTypedArrayBase>(O2REG(Loadi16));
3530
        int16_t *basePtr = reinterpret_cast<int16_t *>(mem->begin(runtime));
3531
        const uint32_t addr = (uint32_t)(int32_t)(O3REG(Loadi16).getNumber());
3532
        O1REG(Loadi16) =
3533
            HermesValue::encodeUntrustedNumberValue(basePtr[addr >> 1]);
3534
        ip = NEXTINST(Loadi16);
3535
        DISPATCH;
3536
      }
3537
      CASE(Loadu16) {
3538
        auto *mem = vmcast<JSTypedArrayBase>(O2REG(Loadu16));
3539
        uint16_t *basePtr = reinterpret_cast<uint16_t *>(mem->begin(runtime));
3540
        const uint32_t addr = (uint32_t)(int32_t)(O3REG(Loadu16).getNumber());
3541
        O1REG(Loadu16) =
3542
            HermesValue::encodeUntrustedNumberValue(basePtr[addr >> 1]);
3543
        ip = NEXTINST(Loadu16);
3544
        DISPATCH;
3545
      }
3546
      CASE(Loadi32) {
3547
        auto *mem = vmcast<JSTypedArrayBase>(O2REG(Loadi32));
3548
        int32_t *basePtr = reinterpret_cast<int32_t *>(mem->begin(runtime));
3549
        const uint32_t addr = (uint32_t)(int32_t)(O3REG(Loadi32).getNumber());
3550
        O1REG(Loadi32) =
3551
            HermesValue::encodeUntrustedNumberValue(basePtr[addr >> 2]);
3552
        ip = NEXTINST(Loadi32);
3553
        DISPATCH;
3554
      }
3555
      CASE(Loadu32) {
3556
        auto *mem = vmcast<JSTypedArrayBase>(O2REG(Loadu32));
3557
        uint32_t *basePtr = reinterpret_cast<uint32_t *>(mem->begin(runtime));
3558
        const uint32_t addr = (uint32_t)(int32_t)(O3REG(Loadu32).getNumber());
3559
        O1REG(Loadu32) = HermesValue::encodeUntrustedNumberValue(
3560
            (int32_t)(basePtr[addr >> 2]));
3561
        ip = NEXTINST(Loadu32);
3562
        DISPATCH;
3563
      }
3564
3565
      CASE(Store8) {
3566
        auto *mem = vmcast<JSTypedArrayBase>(O1REG(Store8));
3567
        int8_t *basePtr = reinterpret_cast<int8_t *>(mem->begin(runtime));
3568
        const uint32_t addr = (uint32_t)(int32_t)(O2REG(Store8).getNumber());
3569
        basePtr[addr] = (int8_t)(int32_t)(O3REG(Store8).getNumber());
3570
        ip = NEXTINST(Store8);
3571
        DISPATCH;
3572
      }
3573
      CASE(Store16) {
3574
        auto *mem = vmcast<JSTypedArrayBase>(O1REG(Store16));
3575
        int16_t *basePtr = reinterpret_cast<int16_t *>(mem->begin(runtime));
3576
        const uint32_t addr = (uint32_t)(int32_t)(O2REG(Store16).getNumber());
3577
        basePtr[addr >> 1] = (int16_t)(int32_t)(O3REG(Store16).getNumber());
3578
        ip = NEXTINST(Store16);
3579
        DISPATCH;
3580
      }
3581
      CASE(Store32) {
3582
        auto *mem = vmcast<JSTypedArrayBase>(O1REG(Store32));
3583
        int32_t *basePtr = reinterpret_cast<int32_t *>(mem->begin(runtime));
3584
        const uint32_t addr = (uint32_t)(int32_t)(O2REG(Store32).getNumber());
3585
        basePtr[addr >> 2] = (int32_t)(O3REG(Store32).getNumber());
3586
        // A nop for now.
3587
        ip = NEXTINST(Store32);
3588
        DISPATCH;
3589
      }
3590
#endif
3591
3592
0
      CASE(_last) {
3593
0
        hermes_fatal("Invalid opcode _last");
3594
0
      }
3595
0
    }
3596
3597
0
    hermes_fatal(
3598
0
        "All opcodes should dispatch to the next and not fallthrough "
3599
0
        "to here");
3600
3601
  // We arrive here if we couldn't allocate the registers for the current frame.
3602
0
  stackOverflow:
3603
0
    CAPTURE_IP(runtime.raiseStackOverflow(
3604
0
        Runtime::StackOverflowKind::JSRegisterStack));
3605
3606
  // We arrive here when we raised an exception in a callee, but we don't want
3607
  // the callee to be able to handle it.
3608
0
  handleExceptionInParent:
3609
    // Restore the caller code block and IP.
3610
0
    curCodeBlock = FRAME.getSavedCodeBlock();
3611
0
    ip = FRAME.getSavedIP();
3612
3613
    // Pop to the previous frame where technically the error happened.
3614
0
    frameRegs = &runtime.restoreStackAndPreviousFrame(FRAME).getFirstLocalRef();
3615
3616
    // If we are coming from native code, return.
3617
0
    if (!curCodeBlock)
3618
0
      return ExecutionStatus::EXCEPTION;
3619
3620
  // Handle the exception.
3621
30
  exception:
3622
30
    UPDATE_OPCODE_TIME_SPENT;
3623
30
    assert(
3624
30
        !runtime.thrownValue_.isEmpty() &&
3625
30
        "thrownValue unavailable at exception");
3626
3627
30
    bool catchable = true;
3628
    // If this is an Error object that was thrown internally, it didn't have
3629
    // access to the current codeblock and IP, so collect the stack trace here.
3630
30
    if (auto *jsError = dyn_vmcast<JSError>(runtime.thrownValue_)) {
3631
30
      catchable = jsError->catchable();
3632
30
      if (!jsError->getStackTrace()) {
3633
        // Temporarily clear the thrown value for following operations.
3634
26
        CAPTURE_IP_ASSIGN(
3635
26
            auto errorHandle,
3636
26
            runtime.makeHandle(vmcast<JSError>(runtime.thrownValue_)));
3637
26
        runtime.clearThrownValue();
3638
3639
26
        CAPTURE_IP(
3640
26
            JSError::recordStackTrace(
3641
26
                errorHandle, runtime, false, curCodeBlock, ip));
3642
3643
        // Restore the thrown value.
3644
26
        runtime.setThrownValue(errorHandle.getHermesValue());
3645
26
      }
3646
30
    }
3647
3648
30
    gcScope.flushToSmallCount(KEEP_HANDLES);
3649
30
    tmpHandle.clear();
3650
3651
30
#ifdef HERMES_ENABLE_DEBUGGER
3652
30
    if (SingleStep) {
3653
      // If we're single stepping, don't bother with any more checks,
3654
      // and simply signal that we should continue execution with an exception.
3655
0
      state.codeBlock = curCodeBlock;
3656
0
      state.offset = CUROFFSET;
3657
0
      return ExecutionStatus::EXCEPTION;
3658
0
    }
3659
3660
30
    using PauseOnThrowMode = facebook::hermes::debugger::PauseOnThrowMode;
3661
30
    auto mode = runtime.debugger_.getPauseOnThrowMode();
3662
30
    if (mode != PauseOnThrowMode::None) {
3663
0
      if (!runtime.debugger_.isDebugging()) {
3664
        // Determine whether the PauseOnThrowMode requires us to stop here.
3665
0
        bool caught =
3666
0
            runtime.debugger_
3667
0
                .findCatchTarget(InterpreterState(curCodeBlock, CUROFFSET))
3668
0
                .hasValue();
3669
0
        bool shouldStop = mode == PauseOnThrowMode::All ||
3670
0
            (mode == PauseOnThrowMode::Uncaught && !caught);
3671
0
        if (shouldStop) {
3672
          // When runDebugger is invoked after an exception,
3673
          // stepping should never happen internally.
3674
          // Any step is a step to an exception handler, which we do
3675
          // directly here in the interpreter.
3676
          // Thus, the result state should be the same as the input state.
3677
0
          InterpreterState tmpState{curCodeBlock, (uint32_t)CUROFFSET};
3678
0
          CAPTURE_IP_ASSIGN(
3679
0
              ExecutionStatus resultStatus,
3680
0
              runtime.debugger_.runDebugger(
3681
0
                  Debugger::RunReason::Exception, tmpState));
3682
0
          (void)resultStatus;
3683
0
          assert(
3684
0
              tmpState == InterpreterState(curCodeBlock, CUROFFSET) &&
3685
0
              "not allowed to step internally in a pauseOnThrow");
3686
0
          gcScope.flushToSmallCount(KEEP_HANDLES);
3687
0
        }
3688
0
      }
3689
0
    }
3690
30
#endif
3691
3692
30
    int32_t handlerOffset = 0;
3693
3694
    // If the exception is not catchable, skip found catch blocks.
3695
30
    while (((handlerOffset = curCodeBlock->findCatchTargetOffset(CUROFFSET)) ==
3696
30
            -1) ||
3697
30
           !catchable) {
3698
30
      PROFILER_EXIT_FUNCTION(curCodeBlock);
3699
3700
30
#ifdef HERMES_MEMORY_INSTRUMENTATION
3701
30
      runtime.popCallStack();
3702
30
#endif
3703
3704
      // Restore the code block and IP.
3705
30
      curCodeBlock = FRAME.getSavedCodeBlock();
3706
30
      ip = FRAME.getSavedIP();
3707
3708
      // Pop a stack frame.
3709
30
      frameRegs =
3710
30
          &runtime.restoreStackAndPreviousFrame(FRAME).getFirstLocalRef();
3711
3712
30
      SLOW_DEBUG(
3713
30
          dbgs() << "function exit with exception: restored stackLevel="
3714
30
                 << runtime.getStackLevel() << "\n");
3715
3716
      // Are we returning to native code?
3717
30
      if (!curCodeBlock) {
3718
30
        SLOW_DEBUG(
3719
30
            dbgs()
3720
30
            << "function exit with exception: returning to native code\n");
3721
30
        return ExecutionStatus::EXCEPTION;
3722
30
      }
3723
3724
30
      assert(
3725
0
          isCallType(ip->opCode) &&
3726
0
          "return address is not Call-type instruction");
3727
0
    }
3728
3729
0
    INIT_STATE_FOR_CODEBLOCK(curCodeBlock);
3730
3731
0
    ip = IPADD(handlerOffset - CUROFFSET);
3732
0
  }
3733
1.64k
}
Unexecuted instantiation: hermes::vm::CallResult<hermes::vm::HermesValue, (hermes::vm::detail::CallResultSpecialize)2> hermes::vm::Interpreter::interpretFunction<true, false>(hermes::vm::Runtime&, hermes::vm::InterpreterState&)
Unexecuted instantiation: hermes::vm::CallResult<hermes::vm::HermesValue, (hermes::vm::detail::CallResultSpecialize)2> hermes::vm::Interpreter::interpretFunction<false, true>(hermes::vm::Runtime&, hermes::vm::InterpreterState&)
Unexecuted instantiation: hermes::vm::CallResult<hermes::vm::HermesValue, (hermes::vm::detail::CallResultSpecialize)2> hermes::vm::Interpreter::interpretFunction<true, true>(hermes::vm::Runtime&, hermes::vm::InterpreterState&)
3734
3735
} // namespace vm
3736
} // namespace hermes
3737
3738
#undef DEBUG_TYPE