bool JSPropertyNameIterator::next(ExecState* exec, JSValue& output)
{
    if (m_enumerationPhase == EnumerationPhase::IndexedNames) {
        for (; m_cursor < m_propertyNameEnumerator->indexedLength();) {
            uint32_t index = m_cursor++;
            if (m_iteratedObject->hasProperty(exec, index)) {
                output = jsString(exec, Identifier::from(exec, index).string());
                return true;
            }
        }
        m_cursor = 0;
        m_enumerationPhase = EnumerationPhase::StructureNames;
    }

    if (m_enumerationPhase == EnumerationPhase::StructureNames) {
        for (; m_cursor < m_propertyNameEnumerator->endStructurePropertyIndex();) {
            uint32_t index = m_cursor++;
            JSString* propertyName = m_propertyNameEnumerator->propertyNameAtIndex(index);
            ASSERT(propertyName);
            if (m_iteratedObject->structure(exec->vm())->id() == m_propertyNameEnumerator->cachedStructureID()) {
                output = propertyName;
                return true;
            }

            if (m_iteratedObject->hasProperty(exec, propertyName->toIdentifier(exec))) {
                output = propertyName;
                return true;
            }
        }
        ASSERT(m_cursor >= m_propertyNameEnumerator->endStructurePropertyIndex());
        // Use the same m_cursor in the GenericNames phase.
        m_enumerationPhase = EnumerationPhase::GenericNames;
    }

    if (m_enumerationPhase == EnumerationPhase::GenericNames) {
        for (; m_cursor < m_propertyNameEnumerator->endGenericPropertyIndex();) {
            uint32_t index = m_cursor++;
            JSString* propertyName = m_propertyNameEnumerator->propertyNameAtIndex(index);
            ASSERT(propertyName);
            if (m_iteratedObject->hasProperty(exec, propertyName->toIdentifier(exec))) {
                output = propertyName;
                return true;
            }
        }
        m_enumerationPhase = EnumerationPhase::Done;
    }

    return false;
}