Coverage Report

Created: 2024-07-18 06:53

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