CallResult<PseudoHandle<>> Interpreter::createObjectFromBuffer(
    Runtime *runtime,
    CodeBlock *curCodeBlock,
    unsigned numLiterals,
    unsigned keyBufferIndex,
    unsigned valBufferIndex) {
  // Fetch any cached hidden class first.
  auto *runtimeModule = curCodeBlock->getRuntimeModule();
  const llvh::Optional<Handle<HiddenClass>> optCachedHiddenClassHandle =
      runtimeModule->findCachedLiteralHiddenClass(
          runtime, keyBufferIndex, numLiterals);
  // Create a new object using the built-in constructor or cached hidden class.
  // Note that the built-in constructor is empty, so we don't actually need to
  // call it.
  auto obj = runtime->makeHandle(
      optCachedHiddenClassHandle.hasValue()
          ? JSObject::create(runtime, optCachedHiddenClassHandle.getValue())
          : JSObject::create(runtime, numLiterals));

  MutableHandle<> tmpHandleKey(runtime);
  MutableHandle<> tmpHandleVal(runtime);
  auto &gcScope = *runtime->getTopGCScope();
  auto marker = gcScope.createMarker();

  auto genPair = curCodeBlock->getObjectBufferIter(
      keyBufferIndex, valBufferIndex, numLiterals);
  auto keyGen = genPair.first;
  auto valGen = genPair.second;

  if (optCachedHiddenClassHandle.hasValue()) {
    uint32_t propIndex = 0;
    // keyGen should always have the same amount of elements as valGen
    while (valGen.hasNext()) {
#ifndef NDEBUG
      {
        // keyGen points to an element in the key buffer, which means it will
        // only ever generate a Number or a Symbol. This means it will never
        // allocate memory, and it is safe to not use a Handle.
        SymbolID stringIdResult{};
        auto key = keyGen.get(runtime);
        if (key.isSymbol()) {
          stringIdResult = ID(key.getSymbol().unsafeGetIndex());
        } else {
          tmpHandleKey = HermesValue::encodeDoubleValue(key.getNumber());
          auto idRes = valueToSymbolID(runtime, tmpHandleKey);
          assert(
              idRes != ExecutionStatus::EXCEPTION &&
              "valueToIdentifier() failed for uint32_t value");
          stringIdResult = **idRes;
        }
        NamedPropertyDescriptor desc;
        auto pos = HiddenClass::findProperty(
            optCachedHiddenClassHandle.getValue(),
            runtime,
            stringIdResult,
            PropertyFlags::defaultNewNamedPropertyFlags(),
            desc);
        assert(
            pos &&
            "Should find this property in cached hidden class property table.");
        assert(
            desc.slot == propIndex &&
            "propIndex should be the same as recorded in hidden class table.");
      }
#endif
      // Explicitly make sure valGen.get() is called before obj.get() so that
      // any allocation in valGen.get() won't invalidate the raw pointer
      // retruned from obj.get().
      auto val = valGen.get(runtime);
      JSObject::setNamedSlotValue(obj.get(), runtime, propIndex, val);
      gcScope.flushToMarker(marker);
      ++propIndex;
    }
  } else {
    // keyGen should always have the same amount of elements as valGen
    while (keyGen.hasNext()) {
      // keyGen points to an element in the key buffer, which means it will
      // only ever generate a Number or a Symbol. This means it will never
      // allocate memory, and it is safe to not use a Handle.
      auto key = keyGen.get(runtime);
      tmpHandleVal = valGen.get(runtime);
      if (key.isSymbol()) {
        auto stringIdResult = ID(key.getSymbol().unsafeGetIndex());
        if (LLVM_UNLIKELY(
                JSObject::defineNewOwnProperty(
                    obj,
                    runtime,
                    stringIdResult,
                    PropertyFlags::defaultNewNamedPropertyFlags(),
                    tmpHandleVal) == ExecutionStatus::EXCEPTION)) {
          return ExecutionStatus::EXCEPTION;
        }
      } else {
        tmpHandleKey = HermesValue::encodeDoubleValue(key.getNumber());
        if (LLVM_UNLIKELY(
                !JSObject::defineOwnComputedPrimitive(
                     obj,
                     runtime,
                     tmpHandleKey,
                     DefinePropertyFlags::getDefaultNewPropertyFlags(),
                     tmpHandleVal)
                     .getValue())) {
          return ExecutionStatus::EXCEPTION;
        }
      }
      gcScope.flushToMarker(marker);
    }
  }
  tmpHandleKey.clear();
  tmpHandleVal.clear();

  // Hidden class in dictionary mode can't be shared.
  HiddenClass *const clazz = obj->getClass(runtime);
  if (!optCachedHiddenClassHandle.hasValue() && !clazz->isDictionary()) {
    assert(
        numLiterals == clazz->getNumProperties() &&
        "numLiterals should match hidden class property count.");
    assert(
        clazz->getNumProperties() < 256 &&
        "cached hidden class should have property count less than 256");
    runtimeModule->tryCacheLiteralHiddenClass(runtime, keyBufferIndex, clazz);
  }

  return createPseudoHandle(HermesValue::encodeObjectValue(*obj));
}